[Zrouter-src] ZRouter.org: push to ZRouter profiles/lua_web_ui/files/etc/dhcli...
zrouter-src at zrouter.org
zrouter-src at zrouter.org
Thu Sep 20 12:54:09 UTC 2012
details: http://zrouter.org/hg/zrouter//rev/367c29234e4c
changeset: 440:367c29234e4c
user: Aleksandr Rybalko <ray at ddteam.net>
date: Thu Sep 20 15:21:54 2012 +0300
description:
Introduce LUA WEB UI.
diffstat:
profiles/lua_web_ui/files/etc/dhclient-script | 66 +
profiles/lua_web_ui/files/etc/favicon.ico | Bin
profiles/lua_web_ui/files/etc/mpd-linkdown | 50 +
profiles/lua_web_ui/files/etc/mpd-linkup | 55 +
profiles/lua_web_ui/files/etc/racoon/phase1-down.sh | 28 +
profiles/lua_web_ui/files/etc/racoon/phase1-up.sh | 28 +
profiles/lua_web_ui/files/etc/racoon/racoon.conf | 31 +
profiles/lua_web_ui/files/etc/rc.d/collector | 24 +
profiles/lua_web_ui/files/etc/rc.d/devd | 27 +
profiles/lua_web_ui/files/etc/rc.d/httpd | 27 +
profiles/lua_web_ui/files/etc/www/collector.lua | 268 +
profiles/lua_web_ui/files/etc/www/collector.sh | 19 +
profiles/lua_web_ui/files/etc/www/config.xml | 274 ++
profiles/lua_web_ui/files/etc/www/devd.lua | 263 +
profiles/lua_web_ui/files/etc/www/devd.sh | 14 +
profiles/lua_web_ui/files/etc/www/htdocs/Administration.config.html | 19 +
profiles/lua_web_ui/files/etc/www/htdocs/Administration.firmware.html | 20 +
profiles/lua_web_ui/files/etc/www/htdocs/Administration.info.html | 16 +
profiles/lua_web_ui/files/etc/www/htdocs/Administration.users.html | 21 +
profiles/lua_web_ui/files/etc/www/htdocs/Advanced.PPP.html | 8 +
profiles/lua_web_ui/files/etc/www/htdocs/Basic.lan.html | 21 +
profiles/lua_web_ui/files/etc/www/htdocs/Basic.wan.html | 46 +
profiles/lua_web_ui/files/etc/www/htdocs/Basic.wlan.html | 18 +
profiles/lua_web_ui/files/etc/www/htdocs/Security.IPSec.html | 85 +
profiles/lua_web_ui/files/etc/www/htdocs/Security.OpenVPN.html | 9 +
profiles/lua_web_ui/files/etc/www/htdocs/Security.SSH.html | 9 +
profiles/lua_web_ui/files/etc/www/htdocs/cmd.xml | 125 +
profiles/lua_web_ui/files/etc/www/htdocs/config.dat | 10 +
profiles/lua_web_ui/files/etc/www/htdocs/css/anim.css | 131 +
profiles/lua_web_ui/files/etc/www/htdocs/css/router.css | 290 ++
profiles/lua_web_ui/files/etc/www/htdocs/event.xml | 108 +
profiles/lua_web_ui/files/etc/www/htdocs/footer.html | 2 +
profiles/lua_web_ui/files/etc/www/htdocs/header.html | 23 +
profiles/lua_web_ui/files/etc/www/htdocs/home_sys.html | 50 +
profiles/lua_web_ui/files/etc/www/htdocs/img/FreeBSD_logo.png | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/banner.jpg | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/config.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/folder.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/help.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/home.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/join.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/joinbottom.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/line.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/logout.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/minus.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/minusbottom.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/monitor.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/open_file.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/open_folder.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/plus.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/plusbottom.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/sys.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/text.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/themespacer.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/tool.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar.jpg | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar_v.jpg | Bin
profiles/lua_web_ui/files/etc/www/htdocs/img/triangle.gif | Bin
profiles/lua_web_ui/files/etc/www/htdocs/index.html | 102 +
profiles/lua_web_ui/files/etc/www/htdocs/js/ajax.js | 107 +
profiles/lua_web_ui/files/etc/www/htdocs/js/defineMyTree.js | 77 +
profiles/lua_web_ui/files/etc/www/htdocs/js/tree.js | 1360 ++++++++++
profiles/lua_web_ui/files/etc/www/htdocs/js/ua.js | 116 +
profiles/lua_web_ui/files/etc/www/htdocs/js/utils.js | 475 +++
profiles/lua_web_ui/files/etc/www/htdocs/js/view.js | 18 +
profiles/lua_web_ui/files/etc/www/htdocs/js/wizard.js | 47 +
profiles/lua_web_ui/files/etc/www/htdocs/jstree_table.html | 41 +
profiles/lua_web_ui/files/etc/www/htdocs/vaps.lua | 134 +
profiles/lua_web_ui/files/etc/www/httpd.lua | 1290 +++++++++
profiles/lua_web_ui/files/etc/www/httpd.sh | 17 +
profiles/lua_web_ui/files/etc/www/lib/base64.lua | 35 +
profiles/lua_web_ui/files/etc/www/lib/bit.lua | 29 +
profiles/lua_web_ui/files/etc/www/lib/conf.lua | 158 +
profiles/lua_web_ui/files/etc/www/lib/dhcpd.lua | 106 +
profiles/lua_web_ui/files/etc/www/lib/handler.lua | 305 ++
profiles/lua_web_ui/files/etc/www/lib/hostapd.lua | 143 +
profiles/lua_web_ui/files/etc/www/lib/ipcalc.lua | 58 +
profiles/lua_web_ui/files/etc/www/lib/ltn12.lua | 292 ++
profiles/lua_web_ui/files/etc/www/lib/mime.lua | 87 +
profiles/lua_web_ui/files/etc/www/lib/mpd.lua | 315 ++
profiles/lua_web_ui/files/etc/www/lib/node.lua | 68 +
profiles/lua_web_ui/files/etc/www/lib/pidfile.lua | 69 +
profiles/lua_web_ui/files/etc/www/lib/racoon.lua | 368 ++
profiles/lua_web_ui/files/etc/www/lib/socket.lua | 133 +
profiles/lua_web_ui/files/etc/www/lib/socket/ftp.lua | 281 ++
profiles/lua_web_ui/files/etc/www/lib/socket/http.lua | 350 ++
profiles/lua_web_ui/files/etc/www/lib/socket/smtp.lua | 251 +
profiles/lua_web_ui/files/etc/www/lib/socket/tp.lua | 123 +
profiles/lua_web_ui/files/etc/www/lib/socket/url.lua | 297 ++
profiles/lua_web_ui/files/etc/www/lib/table.save-0.94.lua | 183 +
profiles/lua_web_ui/files/etc/www/lib/test.lua | 31 +
profiles/lua_web_ui/files/etc/www/lib/utils.lua | 328 ++
profiles/lua_web_ui/files/etc/www/lib/xml.lua | 472 +++
profiles/lua_web_ui/profile.mk | 13 +
94 files changed, 10464 insertions(+), 0 deletions(-)
diffs (10791 lines):
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/dhclient-script
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/dhclient-script Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+#LOG=/tmp/DHCLIENT-SCRIPT.log
+LOG=/dev/null
+
+touch ${LOG}
+echo "DHCLIENT-SCRIPT: $*" >> ${LOG}
+#set >> ${LOG}
+echo >> ${LOG}
+
+case ${reason} in
+ARPSEND)
+ # TODO
+ ;;
+
+ARPCHECK)
+ # TODO
+ ;;
+
+EXPIRE)
+ # TODO
+ ;;
+
+PREINIT)
+ # TODO
+ ;;
+
+REBOOT|BOUND|RENEW)
+ #interface=wan0
+ #new_broadcast_address=192.168.1.255
+ #new_dhcp_lease_time=3600
+ #new_dhcp_message_type=5
+ #new_dhcp_server_identifier=192.168.1.3
+ #new_domain_name_servers='192.168.1.3 192.168.1.3'
+ #new_expiry=4137
+ #new_ip_address=192.168.1.5
+ #new_network_number=192.168.1.0
+ #new_routers=192.168.1.3
+ #new_subnet_mask=255.255.255.0
+ #reason=REBOOT
+ ifconfig ${interface} ${new_ip_address} netmask ${new_subnet_mask}
+ echo "DHCP: iface=${interface} ip=${new_ip_address} netmask=${new_subnet_mask} route=${new_routers} dns=${new_domain_name_servers}" >> ${LOG}
+ query="cmd=event"
+ query="${query}&state=up"
+ query="${query}&iface=${interface}"
+ query="${query}&gw=${new_routers}"
+ query="${query}&ip=${new_ip_address}"
+ query="${query}&netmask=${new_subnet_mask}"
+ query="${query}&dhclient_reason=${reason}"
+ query="${query}&dhclient_lease_time=${new_dhcp_lease_time}"
+ query="${query}&dhclient_message_type=${new_dhcp_message_type}"
+ query="${query}&dhclient_server_identifier=${new_dhcp_server_identifier}"
+ query="${query}&dhclient_expiry=${new_expiry}"
+ i=1
+ for dns in ${new_domain_name_servers} ; do
+ query="${query}&dns${i}=${dns}"
+ i=$(( ${i} + 1 ))
+ done
+
+ # Notify configuration handler
+ fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+ ;;
+*)
+ ;;
+esac
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/favicon.ico
Binary file profiles/lua_web_ui/files/etc/favicon.ico has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/mpd-linkdown
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/mpd-linkdown Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+LOG=/tmp/mpd-linkdown.log
+
+touch ${LOG}
+echo "mpd-linkdown $*" >> ${LOG}
+#set >> ${LOG}
+echo >> ${LOG}
+
+interface=$1
+proto=$2
+localip=$3
+remoteip=$4
+authname=$5
+
+echo $#
+case $# in
+ 6)
+ dns1="8.8.8.8"
+ dns2="8.8.4.4"
+ peeraddress=$6
+ ;;
+ 7)
+ dns1=$6
+ dns2="8.8.8.8"
+ peeraddress=$7
+ ;;
+ 8)
+ dns1=$6
+ dns2=$7
+ peeraddress=$8
+ ;;
+esac
+
+echo "MPD: iface=${interface} proto = ${proto} localip=${localip} remoteip=${remoteip} dns1=${dns1} dns2=${dns2} peeraddress=${peeraddress}" >> ${LOG}
+
+query="cmd=event"
+query="${query}&state=down"
+query="${query}&iface=${interface}"
+query="${query}&proto=${proto}"
+query="${query}&gw=${remoteip}"
+query="${query}&ip=${localip}"
+#query="${query}&dns1=${dns1}"
+#query="${query}&dns2=${dns2}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/mpd-linkup
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/mpd-linkup Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,55 @@
+#!/bin/sh
+
+#
+# mpd-linkup ng0 inet 95.81.35.177/32 195.128.182.55 - dns1 195.128.182.40 dns2 195.128.182.41 [12]
+#
+
+LOG=/tmp/mpd-linkup.log
+
+touch ${LOG}
+echo "mpd-linkup $*" >> ${LOG}
+#set >> ${LOG}
+echo >> ${LOG}
+
+interface=$1
+proto=$2
+localip=$3
+remoteip=$4
+authname=$5
+
+case $# in
+6)
+ dns1="8.8.8.8"
+ dns2="8.8.4.4"
+ peeraddress=$6
+ ;;
+7)
+ dns1=$6
+ dns2="8.8.8.8"
+ peeraddress=$7
+ ;;
+8)
+ dns1=$6
+ dns2=$7
+ peeraddress=$8
+ ;;
+esac
+
+dns1=${dns1#dns1 }
+dns2=${dns2#dns2 }
+
+echo "MPD: iface=${interface} proto = ${proto} localip=${localip} remoteip=${remoteip} dns1=${dns1} dns2=${dns2} peeraddress=${peeraddress}" >> ${LOG}
+query="cmd=event"
+query="${query}&state=up"
+query="${query}&iface=${interface}"
+query="${query}&proto=${proto}"
+query="${query}&gw=${remoteip}"
+query="${query}&ip=${localip}"
+query="${query}&dns1=${dns1}"
+query="${query}&dns2=${dns2}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/racoon/phase1-down.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/racoon/phase1-down.sh Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+LOG=/tmp/racoon-phase1-down.log
+
+touch ${LOG}
+echo "phase1-down.sh $*" >> ${LOG}
+
+
+echo $@ >> ${LOG}
+echo "LOCAL_ADDR = ${LOCAL_ADDR} LOCAL_PORT = ${LOCAL_PORT} REMOTE_ADDR = ${REMOTE_ADDR} REMOTE_PORT = ${REMOTE_PORT}" >> ${LOG}
+
+echo >> ${LOG}
+
+query="cmd=event"
+query="${query}&state=down"
+query="${query}&iface=IPSec0" # XXX: should use names for IPSec peers
+query="${query}&gw=${REMOTE_ADDR}:${REMOTE_PORT}"
+query="${query}&ip=${LOCAL_ADDR}:${LOCAL_PORT}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+# XXX: should be handled by httpd/collector
+sh "/var/run/racoon.${REMOTE_ADDR}_down.sh"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/racoon/phase1-up.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/racoon/phase1-up.sh Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+LOG=/tmp/racoon-phase1-up.log
+
+touch ${LOG}
+echo "phase1-up.sh $*" >> ${LOG}
+
+
+echo $@ >> ${LOG}
+echo "LOCAL_ADDR = ${LOCAL_ADDR} LOCAL_PORT = ${LOCAL_PORT} REMOTE_ADDR = ${REMOTE_ADDR} REMOTE_PORT = ${REMOTE_PORT}" >> ${LOG}
+
+echo >> ${LOG}
+
+query="cmd=event"
+query="${query}&state=up"
+query="${query}&iface=IPSec0" # XXX: should use names for IPSec peers
+query="${query}&gw=${REMOTE_ADDR}:${REMOTE_PORT}"
+query="${query}&ip=${LOCAL_ADDR}:${LOCAL_PORT}"
+
+# Notify configuration handler
+fetch -qo - "http://127.0.0.1:8/event.xml?${query}"
+
+# XXX: should be handled by httpd/collector
+sh "/var/run/racoon.${REMOTE_ADDR}_up.sh"
+
+exit 0
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/racoon/racoon.conf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/racoon/racoon.conf Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,31 @@
+path pidfile "/var/run/racoon.pid";
+path pre_shared_key "/var/db/racoon/racoon_psk.txt"; #location of pre-shared key file
+log notify; #log verbosity setting: set to 'notify' when testing and debugging is complete
+
+padding # options are not to be changed
+{
+ maximum_length 20;
+ randomize off;
+ strict_check off;
+ exclusive_tail off;
+}
+
+timer # timing options. change as needed
+{
+ counter 5;
+ interval 20 sec;
+ persend 1;
+# natt_keepalive 15 sec;
+ phase1 30 sec;
+ phase2 15 sec;
+}
+
+listen # address [port] that racoon will listening on
+{
+# isakmp 192.168.90.1 [500];
+# isakmp_natt 192.168.90.1 [4500];
+ adminsock "/var/db/racoon/racoon.sock" "root" "operator" 0660;
+}
+
+include "/var/run/racoon.links.conf";
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/rc.d/collector
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/rc.d/collector Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# PROVIDE: collector
+# REQUIRE: MAIN
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+#[ -z "${collector_enable}" ] && collector_enable="YES"
+collector_enable="YES"
+name="collector"
+command="/etc/www/${name}.sh"
+rcvar=`set_rcvar`
+
+conf_file="/etc/${name}.conf"
+pidfile="/var/run/${name}.pid"
+
+command_args="-P ${pidfile} -B ${conf_file} &"
+#required_files="${conf_file}"
+#required_modules="wlan_xauth wlan_wep wlan_tkip wlan_ccmp"
+#extra_commands="reload"
+
+load_rc_config ${name}
+run_rc_command "$1"
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/rc.d/devd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/rc.d/devd Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# $FreeBSD: src/etc/rc.d/hostapd,v 1.3.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+#
+
+# PROVIDE: devd
+# REQUIRE: MAIN httpd
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+#[ -z "${devd_enable}" ] && devd_enable="YES"
+devd_enable="YES"
+name="devd"
+command="/etc/www/devd.sh"
+rcvar=`set_rcvar`
+
+conf_file="/etc/${name}.conf"
+pidfile="/var/run/${name}.pid"
+
+command_args="-P ${pidfile} -B ${conf_file} &"
+#required_files="${conf_file}"
+#required_modules="wlan_xauth wlan_wep wlan_tkip wlan_ccmp"
+#extra_commands="reload"
+
+load_rc_config ${name}
+run_rc_command "$1"
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/rc.d/httpd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/rc.d/httpd Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# $FreeBSD: src/etc/rc.d/hostapd,v 1.3.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+#
+
+# PROVIDE: httpd
+# REQUIRE: MAIN collector
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+#[ -z "${httpd_enable}" ] && httpd_enable="YES"
+httpd_enable="YES"
+name="httpd"
+command="/etc/www/${name}.sh"
+rcvar=`set_rcvar`
+
+conf_file="/etc/${name}.conf"
+pidfile="/var/run/${name}.pid"
+
+command_args="-P ${pidfile} -B ${conf_file} &"
+#required_files="${conf_file}"
+#required_modules="wlan_xauth wlan_wep wlan_tkip wlan_ccmp"
+#extra_commands="reload"
+
+load_rc_config ${name}
+run_rc_command "$1"
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/collector.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/collector.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,268 @@
+#!/usr/bin/lua
+
+package.path = "./?.lua;/etc/www/lib/?.lua;./lib/?.lua";
+package.cpath =
+ "/lib/?.so;/usr/lib/?.so;/usr/lib/lua/?.so;" ..
+ "/lib/lua?.so;/usr/lib/lua?.so;/usr/lib/lua/lua?.so;" ..
+ "/lib/?-core.so;/usr/lib/?-core.so;/usr/lib/lua/?-core.so;" ..
+ "/lib/?/core.so;/usr/lib/?/core.so;/usr/lib/lua/?/core.so;";
+
+host = host or "127.0.0.1";
+port = port or "8";
+
+serverhost = serverhost or "127.0.0.1";
+serverport = serverport or "80";
+
+-- Globals
+r = {}; -- Runtime varibles structure
+rquery = {};
+queue = {};
+local internet_led = nil;
+
+--
+-- Utility function: URL encoding function
+--
+function urlEncode(str)
+ if (str) then
+ str = string.gsub (str, "\n", "\r\n")
+ str = string.gsub (str, "([^%w ])",
+ function (c) return string.format ("%%%02X", string.byte(c)) end)
+ str = string.gsub (str, " ", "+")
+ end
+ return str
+end
+
+
+--
+-- Utility function: URL decode function
+--
+function urlDecode(str)
+ str = string.gsub (str, "+", " ")
+ str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end)
+ str = string.gsub (str, "\r\n", "\n")
+ return str
+end
+
+-- convert name1=value1&name2=val+ue%2F2
+-- to table {"name1"="value1", "name2"="val ue/2"}
+function parse_query(query)
+ local parsed = {};
+ local pos = 0;
+
+ query = string.gsub(query, "&", "&");
+ query = string.gsub(query, "<", "<");
+ query = string.gsub(query, ">", ">");
+
+ local function ginsert(qstr)
+ local first, last = string.find(qstr, "=");
+ if first then
+ local key = urlDecode(string.sub(qstr, 0, first-1));
+ local value = urlDecode(string.sub(qstr, first+1));
+ parsed[key] = value;
+ end
+ end
+
+ while true do
+ local first, last = string.find(query, "&", pos);
+ if first then
+ ginsert(string.sub(query, pos, first-1));
+ pos = last+1;
+ else
+ ginsert(string.sub(query, pos));
+ break;
+ end
+ end
+ return parsed;
+end
+
+function process(q, queryline)
+
+ if q["cmd"] == "event" then
+ q["timestamp"] = os.date("%Y-%m-%d %H:%M:%S");
+
+ local iface = q["iface"];
+
+ if not iface then
+ return ("collector.lua: ERROR: Interface not defined");
+ end
+
+ if type(r[iface]) ~= "table" then r[iface] = {}; end
+-- rquery[iface] = queryline;
+ -- First element processed last (implement FIFO)
+ table.insert(queue, 1, {handled=false, query=queryline, qt=q});
+
+ for k,v in pairs(q) do
+ if (k ~= "iface") and (k ~= "cmd") then
+ r[iface][k] = v;
+ end
+ end
+ if q["state"] == "up" then
+ -- XXX: should not be here
+ -- XXX: must check exit code
+ if r[iface]["gw"] then
+ exitcode = os.execute(
+ "route change default " .. r[iface]["gw"] .." > /dev/null 2>&1 || " ..
+ "route add default " .. r[iface]["gw"] .." > /dev/null 2>&1"
+ );
+ if internet_led then
+ internet_led:set(1);
+ end
+ end
+ local dns = {};
+ if q["dns1"] and q["dns1"]:len() >= 7 then
+ table.insert(dns, q["dns1"]);
+ end
+ if q["dns2"] and q["dns2"]:len() >= 7 then
+ table.insert(dns, q["dns2"]);
+ end
+ if table.getn(dns) > 0 then
+ resolv_conf = io.open("/etc/resolv.conf", "w");
+ for i,v in ipairs(dns) do
+ -- print("nameserver " .. v);
+ resolv_conf:write("nameserver " .. v .. "\n");
+ end
+ resolv_conf:close();
+ end
+ end
+ if q["state"] == "down" then
+ if r[iface]["gw"] then
+ if internet_led then
+ internet_led:set(0);
+ end
+ end
+ end
+
+ return "OK";
+
+ elseif q["cmd"] == "revent" then
+
+ iface = q["iface"];
+
+ if r[iface] then
+ local ret = nil;
+
+ for k,v in pairs(r[iface]) do
+ if ret then
+ ret = ret .. "&" .. urlEncode(k) .. "=" .. urlEncode(v);
+ else
+ ret = urlEncode(k) .. "=" .. urlEncode(v);
+ end
+ end
+
+ return (ret);
+ else
+ return ("ERROR: no data for interface " .. iface);
+ end
+ else
+ return ("ERROR: unknown command");
+ end
+end
+
+function call_server(http, q)
+ local query = "http://127.0.0.1:80/event.xml?" .. q;
+
+ local body, code, headers = http.request(query);
+
+ if code == 200 then
+ return (true);
+ else
+ return (nil);
+ end
+
+end
+
+function getopt(args, opts)
+ i=1;
+ while i < table.getn(arg) do
+ if arg[i]:match("^-") then
+ opts[arg[i]] = arg[i+1];
+ i = i + 1;
+ end
+ i = i + 1;
+ end
+ return (opts);
+end
+
+
+
+opts = {};
+opts["-P"] = "/var/run/collector.pid";
+
+if arg then
+ opts = getopt(arg, opts);
+end
+
+
+-- Check pidfile
+dofile("lib/pidfile.lua");
+pidfile(opts["-P"]);
+
+dofile("lib/led.lua");
+
+internet_led = Led:new_from_env("INTERNET_LED");
+
+socket = require("socket");
+http = require("socket.http");
+server = assert(socket.bind(host, port));
+server:settimeout(5);
+
+
+while 1 do
+ local method, path, query, major, minor;
+
+ local control = server:accept();
+
+ if control then
+ while 1 do
+ local data, err = control:receive();
+ if not err then
+ local q;
+ _, _, method, path, q, major, minor = string.find(data, "([A-Z]+) (.-)%?(.-) HTTP/(%d).(%d)");
+ if not query and q then
+ query = q;
+ break;
+ end
+ else
+ break;
+ end
+ end
+
+ if query then
+ local q = parse_query(query);
+ if q and q.cmd then
+ assert(control:send(
+ "HTTP/1.0 200 OK\r\n" ..
+ "Server: simple-lua\r\n" ..
+ "Content-type: text/xml\r\n" ..
+ "Connection: close\r\n" ..
+ "\r\n" ..
+ process(q, query)
+ ));
+ end
+ end
+
+ assert(control:close());
+ end
+
+ local n = table.getn(queue);
+ if n > 0 then
+ for i = n,1,-1 do
+ if queue[i].handled ~= true then
+ -- print("queue[" .. i .. "] Will send " .. queue[i].query .. " to main server");
+ if (call_server(http, queue[i].query) == true) then
+ -- print("queue[" .. i .. "] Will delete " .. queue[i].query .. " from queue");
+ queue[i].handled = true;
+ table.remove(queue, i);
+ end
+ end
+ end
+ end
+
+end
+
+os.exit(0);
+
+
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/collector.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/collector.sh Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+
+cd /etc/www
+
+echo $$ > /var/run/collector.sh.pid
+
+INTERNET_LED=$(kenv -q INTERNET_LED)
+INTERNET_LED_INVERT=$(kenv -q INTERNET_LED_INVERT)
+
+export INTERNET_LED INTERNET_LED_INVERT
+
+./collector.lua > /var/log/collector.sh.log 2>&1
+exit 1
+
+while true; do
+ ./collector.lua > /var/log/collector.sh.log 2>&1
+done
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/config.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/config.xml Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,274 @@
+<interfaces>
+ <wan0>
+ <PPPoE enable="false" type="pppoe" onchange="iface_changed('interfaces.wan0.PPPoE')">
+ <action>
+ <create target="socket:127.0.0.1:5005" type="socket">
+ <message></message>
+ </create>
+ </action>
+ <nat enable="true"></nat>
+ <name>PPPoE</name>
+ <username>pppoe1</username>
+ <password>test</password>
+ <service_name></service_name>
+ <device>wan0</device>
+ <default_route>true</default_route>
+ <!-- flags -> FORCE='overwrite received', DEFAULT='used if no received' -->
+ <ipaddr flags="DEFAULT,FORCE">10.0.0.1/32</ipaddr>
+ <gateway flags="DEFAULT">10.0.0.2</gateway>
+ <!-- <ip6addr></ip6addr> -->
+ <!-- Values holders -->
+ <dns1></dns1>
+ <dns2></dns2>
+ <name>wan0pppoe</name>
+ <group>WAN</group>
+ <cost>10</cost>
+ </PPPoE>
+ <PPP enable="false" type="modem" onchange="iface_changed('interfaces.wan0.PPP')">
+ <action>
+ <up target="socket:127.0.0.1:5005" type="socket"></up>
+ <destroy target="socket:127.0.0.1:5005" type="socket"></destroy>
+ <down target="socket:127.0.0.1:5005" type="socket"></down>
+ <create target="socket:127.0.0.1:5005" type="socket"></create>
+ <destroy target="socket:127.0.0.1:5005" type="socket"></destroy>
+ </action>
+ <name>3G</name>
+ <nat enable="true"></nat>
+ <username>IT</username>
+ <password>IT</password>
+ <phone>#777</phone>
+ <init_string></init_string>
+ <device>/dev/cuaU0.0</device>
+ <default_route>true</default_route>
+ <!-- flags -> FORCE='overwrite received', DEFAULT='used if no received' -->
+ <ipaddr flags="DEFAULT,FORCE">10.0.0.1/32</ipaddr>
+ <gateway flags="DEFAULT">10.0.0.2</gateway>
+ <!-- <ip6addr></ip6addr> -->
+ <!-- Values holders -->
+ <dns1></dns1>
+ <dns2></dns2>
+ <name>PPP</name>
+ <group>WAN</group>
+ <cost>1000</cost>
+ </PPP>
+ <Static enable="true" type="hw">
+ <nat enable="true"></nat>
+ <dhcp enable="true"></dhcp>
+ <device>wan0</device>
+ <default_route>true</default_route>
+ <!-- flags -> FORCE='overwrite received', DEFAULT='used if no received' -->
+ <ipaddr flags="DEFAULT,FORCE">10.0.0.10/24</ipaddr>
+ <!-- Values holders -->
+ <gateway>10.0.0.1</gateway>
+ <dns1>10.0.0.1</dns1>
+ <dns2>10.0.0.2</dns2>
+ <name>wan0</name>
+ <group>WAN</group>
+ <cost>100</cost>
+ </Static>
+ </wan0>
+ <wlan0 enable="true" type="wlan">
+ <create>
+ <exec>ifconfig wlan0 create wlandev wifi0 wlanmode hostap</exec>
+ </create>
+ <init>
+ <exec>ifconfig wlan0</exec>
+ </init>
+ <wlan_interface>wifi0</wlan_interface>
+ <channel>6</channel>
+ <mode>11ng</mode>
+ <ht40>true</ht40>
+ </wlan0>
+ <wifi0>
+ <init>
+ <exec>ifconfig wifi0 up</exec>
+ </init>
+ </wifi0>
+ <lan0>
+ <init>
+ <!-- exec>ifconfig lan0 up</exec -->
+ </init>
+ </lan0>
+ <bridge0 type="bridge">
+ <create>
+ <exec>ifconfig wlan0 down</exec>
+ <exec>ifconfig lan0 down</exec>
+ <exec>ifconfig bridge0 create addm lan0 addm wlan0 up</exec>
+ <exec>ifconfig bridge0 down</exec>
+ <exec>ifconfig bridge0 ether `kenv LAN_MAC_ADDR`</exec>
+ <exec>ifconfig lan0 up</exec>
+ <exec>ifconfig wlan0 up</exec>
+ <exec>ifconfig bridge0 up</exec>
+ </create>
+ <init>
+ </init>
+ <ipaddr>192.168.0.1/24</ipaddr>
+ <lagg_interfaces>lan0,wlan0</lagg_interfaces>
+ </bridge0>
+</interfaces>
+<switch>
+ <ports>
+ <port id="0" pvid="1" tagged="false"></port>
+ <port id="1" pvid="1" tagged="false"></port>
+ <port id="2" pvid="1" tagged="false"></port>
+ <port id="3" pvid="1" tagged="false"></port>
+ <port id="4" pvid="2" tagged="false"></port>
+ <port id="5" pvid="1" tagged="true"></port>
+ <port id="6" pvid="1" tagged="false"></port>
+ </ports>
+ <vlans>
+ <vlan id="0" vid="1">0,1,2,3,5</vlan>
+ <vlan id="1" vid="2">4,5</vlan>
+ </vlans>
+</switch>
+<dnsrelay enable="false"></dnsrelay>
+<dhcpd>
+ <instances>
+ <instance id="0" enable="true">
+ <interface>bridge0</interface>
+ <domain>dlink.ua</domain>
+ <!-- <domainservers>192.168.0.1</domainservers> -->
+ <default-lease-time>600</default-lease-time>
+ <max-lease-time>7200</max-lease-time>
+ <range>
+ <start>192.168.0.100</start>
+ <end>192.168.0.200</end>
+ </range>
+ </instance>
+ </instances>
+</dhcpd>
+<routes>
+ <default>
+ <source priority="10">interfaces.wan0.DHCP.gateway</source>
+ <source priority="11">interfaces.wan0.PPPoE.gateway</source>
+ <source priority="12">interfaces.wan0.PPP.gateway</source>
+ <source priority="13">interfaces.wan0.Static.gateway</source>
+ <source priority="14">interfaces.wan0.PPTP.gateway</source>
+ <source priority="15">interfaces.wan0.L2TP.gateway</source>
+ </default>
+ <route id="1" enable="false">
+ <net>172.16.0.0/12</net>
+ <gw>192.168.0.2</gw>
+ </route>
+</routes>
+<resolve>
+ <search>dlink.ua</search>
+ <domain>dlink.ua dlink.ru</domain>
+ <options>attempts:5 timeout:10</options>
+ <nameserver order="100">8.8.8.8</nameserver>
+ <nameserver order="101">8.8.4.4</nameserver>
+</resolve>
+<igmp>
+ <instance id="0" enable="false">
+ <up>wan0</up>
+ <down>wlan0</down>
+ </instance>
+ <instance id="0" enable="false">
+ <up>wan0</up>
+ <down>lan0</down>
+ </instance>
+</igmp>
+<info>
+ <hostname>zrouter</hostname>
+ <location>home</location>
+ <firmware>
+ <!-- XXX: version and build date should be here -->
+ <version>???</version>
+ <date>????</date>
+ <update_url>http://www.dlink.ua/files/products/ftp/pub/Router/DIR-620/Firmware/FreeBSD/D-Link_DIR-620-last.txt</update_url>
+ </firmware>
+</info>
+<hostapd>
+ <instance id="0" enable="true">
+ <ieee80211d>1</ieee80211d>
+ <country_code>UA</country_code>
+ <interface>wlan0</interface>
+ <macaddr_acl>0</macaddr_acl>
+ <auth_algs>1</auth_algs>
+ <debug>0</debug>
+ <hw_mode>g</hw_mode>
+ <ctrl_interface>/var/run/hostapd</ctrl_interface>
+ <ctrl_interface_group>wheel</ctrl_interface_group>
+ <ssid>zrouter</ssid>
+ <channel>6</channel>
+ <!-- Open -->
+ <wpa>3</wpa>
+ <!-- WPA -->
+ <!-- <wpa>1</wpa> -->
+ <!-- RSN/WPA2 -->
+ <!-- <wpa>2</wpa> -->
+ <wpa_passphrase>freebsdmall</wpa_passphrase>
+ <wpa_key_mgmt>WPA-PSK</wpa_key_mgmt>
+ <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+ </instance>
+ <instance id="1" enable="false">
+ <ieee80211d>1</ieee80211d>
+ <country_code>UA</country_code>
+ <interface>wlan0</interface>
+ <macaddr_acl>0</macaddr_acl>
+ <auth_algs>1</auth_algs>
+ <debug>0</debug>
+ <hw_mode>g</hw_mode>
+ <ctrl_interface>/var/run/hostapd</ctrl_interface>
+ <ctrl_interface_group>wheel</ctrl_interface_group>
+ <ssid>zrouter</ssid>
+ <!-- WPA -->
+ <!-- <wpa>1</wpa> -->
+ <!-- RSN/WPA2 -->
+ <wpa>2</wpa>
+ <wpa_passphrase>freebsdmall</wpa_passphrase>
+ <wpa_key_mgmt>WPA-PSK</wpa_key_mgmt>
+ <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+ </instance>
+</hostapd>
+<http>
+ <users>
+ <user username="admin" password="admin" group="admin"></user>
+ <user username="user" password="123" group="stat"></user>
+ </users>
+ <!-- host>192.168.0.1</host
+ bind to all, because we need local access also.
+ XXX: we should take care about ipfw deny for that. -->
+ <host>192.168.0.1</host>
+ <port>80</port>
+</http>
+<ipsec>
+ <remote id="0" enable="false">
+ <gateway>10.0.0.2:500</gateway>
+ <exchange_mode>main,aggressive</exchange_mode>
+ <my_identifier>address 10.0.0.1</my_identifier>
+ <peers_identifier>address 10.0.0.2</peers_identifier>
+ <lifetime>time 28800 sec</lifetime>
+ <initial_contact>on</initial_contact>
+ <passive>off</passive>
+ <proposal_check>obey</proposal_check>
+ <nat_traversal>off</nat_traversal>
+ <generate_policy>off</generate_policy>
+ <proposal>
+ <encryption_algorithm>3des</encryption_algorithm>
+ <hash_algorithm>md5</hash_algorithm>
+ <authentication_method>pre_shared_key</authentication_method>
+ <dh_group>5</dh_group>
+ <psk>pskpskpsk</psk>
+ </proposal>
+ </remote>
+ <sainfo id="0" enable="true">
+ <src>address 192.168.0.0/24 any</src>
+ <dst>address 192.168.2.0/24 any</dst>
+ <pfs_group>5</pfs_group>
+ <lifetime>time 3600 sec</lifetime>
+ <encryption_algorithm>3des</encryption_algorithm>
+ <authentication_algorithm>hmac_md5</authentication_algorithm>
+ <compression_algorithm>deflate</compression_algorithm>
+ </sainfo>
+ <setkey>
+ <line>spdadd 192.168.0.0/24 192.168.2.0/24 any -P out ipsec esp/tunnel/10.0.0.1-10.0.0.2/use</line>
+ <line>spdadd 192.168.2.0/24 192.168.0.0/24 any -P in ipsec esp/tunnel/10.0.0.2-10.0.0.1/use</line>
+ <line></line>
+ <line></line>
+ </setkey>
+</ipsec>
+<ntp enable="true">
+ <server id="1">ntp.dlink.com.tw</server>
+ <server id="2">ntp1.dlink.com</server>
+</ntp>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/devd.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/devd.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,263 @@
+#!/usr/bin/lua
+
+package.path = "./?.lua;/etc/www/lib/?.lua;./lib/?.lua";
+package.cpath =
+ "/lib/?.so;/usr/lib/?.so;/usr/lib/lua/?.so;" ..
+ "/lib/lua?.so;/usr/lib/lua?.so;/usr/lib/lua/lua?.so;" ..
+ "/lib/?-core.so;/usr/lib/?-core.so;/usr/lib/lua/?-core.so;" ..
+ "/lib/?/core.so;/usr/lib/?/core.so;/usr/lib/lua/?/core.so;";
+
+serverhost = serverhost or "127.0.0.1";
+serverport = serverport or "80";
+
+-- redirect print to /dev/console
+-- dofile("lib/print_to_console.lua");
+
+-- redirect print to syslog
+dofile("lib/lsyslog.lua");
+syslog_init("devd.lua");
+
+-- urlEncode/urlDecode
+dofile("lib/urlXxcode.lua");
+
+function tab_to_query(t)
+ local ret = "event=devd";
+
+ for k,v in pairs(t) do
+ ret = ret .. "&" .. urlEncode(k) .. "=" .. urlEncode(v);
+ end
+
+ return (ret);
+end
+
+function call_server(config, q)
+ local query = "http://127.0.0.1:80/event.xml?" .. q;
+
+ local body, code, headers = config.http.request(query);
+
+ if code == 200 then
+ return (true);
+ else
+ return (nil);
+ end
+
+end
+
+function exec_output(cmd)
+ fp = io.popen(cmd, "r");
+ data = fp:read("*a");
+ fp:close();
+ return data;
+end
+
+function system_event(config, msg)
+ -- !system=IFNET subsystem=rt0 type=ATTACH
+ -- !system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.1.1
+ -- !system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.1 cdev=ugen0.1 \
+ -- vendor=0x0000 product=0x0000 devclass=0x09 devsubclass=0x00 \
+ -- sernum= release=0x0100 mode=host port=1 parent=dotg0
+ -- !system=GPIO subsystem=pin14 type=PIN_LOW bus=gpiobus0 period=0
+ -- !system=GPIO subsystem=pin14 type=PIN_HIGH bus=gpiobus0 period=0
+
+ function generic_event(m, msg)
+ -- Relay to main control logic
+ local query = "cmd=event" ..
+ "&system=" .. m.system ..
+ "&subsystem=" .. m.subsystem ..
+ "&type=" .. m.type ..
+ "&data=" .. urlEncode(msg);
+ -- cmd=event&iface=wan0&state=linkup;
+ print("devd.lua: query master with \"" .. query .. "\"");
+ if call_server(config, query) == false then
+ -- XXX error handling
+ end
+ end
+
+ local m = {};
+
+ if not msg then
+ return (nil);
+ end
+
+ for k, v in msg:gmatch("(%w+)=(%S+)") do
+ m[k] = v;
+ -- print(k,v);
+ end
+
+ if m.system and m.subsystem and m.type then
+ if m.system == "IFNET" then
+ -- Interfaces
+ -- system=IFNET subsystem=lan0 type=LINK_UP
+ local linkstate;
+ if m.type == "LINK_UP" then
+ if m.subsystem == "lan0" then
+ -- XXX: bug workaround, we have to check why UP does not unplumb iface
+ os.execute("ifconfig lan0 down");
+ os.execute("ifconfig lan0 up");
+ end
+ linkstate = "linkup";
+ elseif m.type == "LINK_DOWN" then
+ linkstate = "linkdown";
+ else
+ generic_event(m, msg);
+ return (nil);
+ end
+ local query = "cmd=event" ..
+ "&iface=" .. urlEncode(m.subsystem) ..
+ "&state=" .. linkstate;
+ -- cmd=event&iface=wan0&state=linkup;
+ if call_server(config, query) == false then
+ -- XXX error handling
+ end
+ elseif m.system == "DEVFS" then
+ -- Device nodes
+ generic_event(m, msg);
+
+ elseif m.system == "USB" then
+ -- USB messages
+ generic_event(m, msg);
+ -- !system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.2 cdev=ugen0.2 vendor=0x1f28 product=0x0021
+ -- devclass=0x00 devsubclass=0x00 sernum="216219360300" release=0x0000
+ -- mode=host interface=0 endpoints=2 intclass=0x08 intsubclass=0x06 intprotocol=0x50
+
+ -- system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.2 cdev=ugen0.2 vendor=0x1f28 product=0x0021
+ -- devclass=0x00 devsubclass=0x00 sernum=%22216219360300%22 release=0x0000 mode=host port=1 parent=ugen0.1
+
+ -- Our usb_modeswitch :)
+ if m.subsystem == "DEVICE" and m.type == "ATTACH" then
+ -- XXX: get that from config
+ m.vendor = m.vendor - 0;
+ m.product = m.product - 0;
+ -- ugen0.2 -> 0.2
+ devid = m.ugen:gsub("ugen", "");
+ if m.vendor == 0x1f28 and m.product == 0x0021 then
+ os.execute("hex2bin " ..
+ "55534243b82e238c24000000800108df200000000000000000000000000000" ..
+ " > /dev/usb/" .. devid .. ".8"); -- EndPoint 8
+ end
+ end
+
+ elseif m.system == "GPIO" then
+ -- GPIO messages
+ generic_event(m, msg);
+
+ -- XXX: should not be hardcoded
+ if m.subsystem == reset_pin and m.bus == "gpiobus0" then
+ if m.type == "PIN_LOW" then
+ -- Pin return to normal state
+ time = tonumber(m.period);
+ -- if hold time between 10 and 15 sec, call httpd to reset to default
+ -- XXX better to send event to httpd, then httpd will decide what to do
+ -- XXX2 but if httpd have wrong config, then he can't start
+ if 10 < time and time < 15 then
+ -- XXX: always do restore config here, because wrong config break httpd yet
+ -- if call_server(config, "restore=config") == false then
+ -- If we can't get success from httpd, then we restore default manualy
+ os.execute("mv /tmp/etc/www/config.xml /tmp/etc/www/config.xml.bak");
+ os.execute("/etc/rc.save_config");
+ os.execute("reboot");
+ -- end
+ os.execute("echo \"devd.lua: User request Reset to Default\" > /dev/console");
+ end
+ elseif m.type == "PIN_HIGH" then
+ -- User push the reset button
+ -- Nothing to do yet
+ else
+ -- Unknown type
+ end
+ end
+ else
+ -- Unknown system
+ end
+ end
+end
+
+function unknown_device(config, msg)
+-- "? at pins=? on gpiobus0"
+end
+
+function device_attached(config, msg)
+-- "+nvram2env0 at on nexus0"
+end
+
+function device_detached(config, msg)
+-- "-nvram2env0 at on nexus0"
+end
+
+
+
+local run = true;
+local config = {};
+config.http = require("socket.http");
+
+reset_pin = exec_output("kenv -q RESET_PIN");
+if not reset_pin then
+ reset_pin = 10;
+end
+reset_pin = string.format("pin%03d", reset_pin);
+
+while run do
+ if not config.d then
+ config.d = io.open("/dev/devctl", "r");
+ end
+ local line = config.d:read("*l");
+ if line then
+ print("devd.lua:DEBUG: got \"" .. line .. "\"");
+ local m, _, t, msg = line:find("^(.)(.*)");
+ if m and t and msg then
+ if t == "!" then
+ system_event(config, msg);
+ elseif t == "?" then
+ unknown_device(config, msg);
+ elseif t == "+" then
+ device_attached(config, msg);
+ elseif t == "-" then
+ device_detached(config, msg);
+ else
+ os.execute("echo \" Message with unknown type received " .. line .. "\" > /dev/console");
+ end
+ end
+ end
+end
+
+
+--[[
+!system=IFNET subsystem=rt0 type=ATTACH
+!system=IFNET subsystem=usbus0 type=ATTACH
+!system=IFNET subsystem=rt28600 type=ATTACH
+!system=IFNET subsystem=lo0 type=ATTACH
+
++nvram2env0 at on nexus0
++clock0 at on nexus0
++rt0 at on nexus0
++rt305x_sysctl0 at on obio0
++rt305x_ic0 at on obio0
++gpioc0 at pins=? on gpiobus0
++gpioreset0 at pins=? on gpiobus0
+? at pins=? on gpiobus0
++gpioled1 at pins=? on gpiobus0
++gpiobus0 at on gpio0
++gpio0 at on obio0
++uart1 at on obio0
++cfid0 at on cfi0
++cfi0 at on obio0
++usbus0 at on dotg0
++dotg0 at on obio0
++rt28600 at on nexus0
++nexus0 at on root0
+
+-- New device node
+!system=DEVFS subsystem=CDEV type=CREATE cdev=usbctl
+!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.1.0
+!system=DEVFS subsystem=CDEV type=CREATE cdev=ugen0.1
+!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/0.1.1
+
+!system=USB subsystem=DEVICE type=ATTACH ugen=ugen0.1 cdev=ugen0.1 vendor=0x0000 product=0x0000 devclass=0x09 devsubclass=0x00 sernum= release=0x0100 mode=host port=1 parent=dotg0
+!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.1 cdev=ugen0.1 vendor=0x0000 product=0x0000 devclass=0x09 devsubclass=0x00 sernum= release=0x0100 mode=host interface=0 endpoints=1 intclass=0x09 intsubclass=0x00 intprotocol=0x00
+!system=DEVFS subsystem=CDEV type=CREATE cdev=cfid0
+!system=DEVFS subsystem=CDEV type=CREATE cdev=map/bootloader
+
+-- Reported GPIO pins
+!system=GPIO subsystem=pin14 type=PIN_LOW bus=gpiobus0 period=0
+!system=GPIO subsystem=pin14 type=PIN_HIGH bus=gpiobus0 period=0
+]]
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/devd.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/devd.sh Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+
+cd /etc/www
+
+echo $$ > /var/run/devd.sh.pid
+
+./devd.lua > /var/log/devd.sh.log 2>&1
+exit 1
+
+while true; do
+ ./devd.lua
+done
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.config.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.config.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,19 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>Device Configuration</h1>
+
+ <h4>Upload Configuration</h4>
+ <form method="post" action="/cmd.xml" enctype="multipart/form-data">
+ <input type="hidden" name="cmd" value="upload_config">
+ <input type="file" name="config" value="">
+ <input type="submit" name="Upload Config" value="Upload Config">
+ </form>
+ <h4>Download Configuration</h4>
+ <form method="post" action="/config.dat" enctype="application/x-www-form-urlencoded">
+ <input type="hidden" name="cmd" value="download_config">
+ <input type="submit" name="Download Config" value="Download Config">
+ </form>
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.firmware.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.firmware.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,20 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>Device Firmware</h1>
+Current Version: <strong>$$$info.firmware.version$$$</strong><br/>
+Build Date:<strong>$$$info.firmware.date$$$</strong><br/>
+
+$$$code:conf_table("Firmware", "Firmware", "info.firmware",
+{
+ { label = "Update URL", type = "node", htmltype = "text", node = "update_url" },
+})$$$
+
+ <h4>Upgrade Firmware</h4>
+ <form method="post" action="/cmd.xml" enctype="application/x-www-form-urlencoded">
+ <input type="hidden" name="cmd" value="upgrade">
+ <input type="submit" name="Start Upgrade" value="Start Upgrade">
+ </form>
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.info.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.info.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,16 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>Device Information</h1>
+Vendor:<strong>$$$info.device.vendor$$$</strong><br/>
+Model:<strong>$$$info.device.model$$$</strong><br/>
+Hardware Revision:<strong>$$$info.device.revision$$$</strong><br/>
+
+$$$code:conf_table("DevInfo", "Device Information", "info",
+{
+ { label = "Hostname", type = "node", htmltype = "text", node = "hostname" },
+ { label = "Location", type = "node", htmltype = "text", node = "location" },
+})$$$
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Administration.users.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Administration.users.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,21 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>Users</h1>
+TODO: Access groups
+$$$code:conf_table("User1Auth", "User 1 auth", "http.users.user[1]",
+{
+ { label = "Username", type = "attr", htmltype = "text", node = ":username" },
+ { label = "Password", type = "attr", htmltype = "text", node = ":password" },
+--[[ { label = "Group", type = "attr", htmltype = "text", node = ":group" },]]
+})$$$
+
+$$$code:conf_table("User2Auth", "User 2 auth", "http.users.user[2]",
+{
+ { label = "Username", type = "attr", htmltype = "text", node = ":username" },
+ { label = "Password", type = "attr", htmltype = "text", node = ":password" },
+--[[ { label = "Group", type = "attr", htmltype = "text", node = ":group" },]]
+})$$$
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Advanced.PPP.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Advanced.PPP.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,8 @@
+$$$code:inc("htdocs/header.html")$$$
+
+ <h1>Advanced PPP options</h1>
+ <h1>Advanced 3G modems options</h1>
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Basic.lan.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Basic.lan.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,21 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>LAN configuration</h1>
+
+$$$code:conf_table("LAN", "LAN", "interfaces.bridge0",
+{
+ { label = "IP Address", type = "node", htmltype = "text", node = "ipaddr" },
+})$$$
+
+$$$code:conf_table("DHCPD", "DHCP server configuration", "dhcpd.instances.instance[1]",
+{
+ { label = "Enabled", type = "attr", htmltype = "checkbox", node = ":enable" },
+ { label = "First IP Address", type = "node", htmltype = "text", node = "range.start" },
+ { label = "Last IP Address", type = "node", htmltype = "text", node = "range.end" },
+ { label = "Default Lease Time", type = "node", htmltype = "text", node = "default-lease-time"},
+ { label = "Max Lease Time", type = "node", htmltype = "text", node = "max-lease-time" },
+})$$$
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Basic.wan.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Basic.wan.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,46 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>Internet connections configuration</h1>
+
+$$$code:conf_table("Static", "Ethernet Interface", "interfaces.wan0.Static",
+{
+ { label = "Enabled", type = "attr", htmltype = "checkbox", node = ":enable" },
+ { label = "Automatic (DHCP)", type = "attr", htmltype = "checkbox", node = "dhcp:enable" },
+ { label = "IP Address", type = "node", htmltype = "text", node = "ipaddr" },
+ { label = "Gateway Address", type = "node", htmltype = "text", node = "gateway" },
+ { label = "DNS Primary", type = "node", htmltype = "text", node = "dns1" },
+ { label = "DNS Secondary", type = "node", htmltype = "text", node = "dns2" },
+ { label = "NAT Enabled", type = "attr", htmltype = "checkbox", node = "nat:enable" }
+})$$$
+
+$$$code:conf_table("PPPoE", "PPPoE", "interfaces.wan0.PPPoE",
+{
+ { label = "Enabled", type = "attr", htmltype = "checkbox", node = ":enable" },
+ { label = "Username", type = "node", htmltype = "text", node = "username" },
+ { label = "Password", type = "node", htmltype = "text", node = "password" },
+ { label = "Service name", type = "node", htmltype = "text", node = "service_name" },
+ { label = "Device", type = "node", htmltype = "text", node = "device" },
+ { label = "IP Address", type = "node", htmltype = "text", node = "ipaddr" },
+ { label = "Gateway Address", type = "node", htmltype = "text", node = "gateway" },
+ { label = "DNS Primary", type = "node", htmltype = "text", node = "dns1" },
+ { label = "DNS Secondary", type = "node", htmltype = "text", node = "dns2" },
+ { label = "NAT Enabled", type = "attr", htmltype = "checkbox", node = "nat:enable" }
+})$$$
+
+$$$code:conf_table("PPP", "PPP (3G)", "interfaces.wan0.PPP",
+{
+ { label = "Enabled", type = "attr", htmltype = "checkbox", node = ":enable" },
+ { label = "Username", type = "node", htmltype = "text", node = "username" },
+ { label = "Password", type = "node", htmltype = "text", node = "password" },
+ { label = "Phone", type = "node", htmltype = "text", node = "phone" },
+ { label = "Init String", type = "node", htmltype = "text", node = "init_string" },
+ { label = "Device", type = "node", htmltype = "text", node = "device" },
+ { label = "IP Address", type = "node", htmltype = "text", node = "ipaddr" },
+ { label = "Gateway Address", type = "node", htmltype = "text", node = "gateway" },
+ { label = "DNS Primary", type = "node", htmltype = "text", node = "dns1" },
+ { label = "DNS Secondary", type = "node", htmltype = "text", node = "dns2" },
+ { label = "NAT Enabled", type = "attr", htmltype = "checkbox", node = "nat:enable" }
+})$$$
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Basic.wlan.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Basic.wlan.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,18 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>Wireless configuration</h1>
+
+$$$code:conf_table("WLAN", "Wireless Access Point configuration", "hostapd.instance[1]",
+{
+ { label = "Enabled", type = "attr", htmltype = "checkbox", node = ":enable" },
+ { label = "Country code (UA)", type = "node", htmltype = "text", node = "country_code" },
+ { label = "wireless iface (wlan0)", type = "node", htmltype = "text", node = "interface" },
+ { label = "Channel (6)", type = "node", htmltype = "text", node = "channel" },
+ { label = "SSID", type = "node", htmltype = "text", node = "ssid" },
+ { label = "WPA mode, 1-WPA, 2-RSN, 3-WPA+RSN", type = "node", htmltype = "text", node = "wpa" },
+ { label = "WPA key", type = "node", htmltype = "text", node = "wpa_passphrase" },
+})$$$
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Security.IPSec.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Security.IPSec.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,85 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>IPSec configuration</h1>
+
+
+<!-- ipsec>
+ <remote id="0" enable="true">
+ <gateway>10.0.0.2:500</gateway>
+ <exchange_mode>main,aggressive</exchange_mode>
+ <my_identifier>address 10.0.0.1</my_identifier>
+ <peers_identifier>address 10.0.0.2</peers_identifier>
+ <lifetime>time 28800 sec</lifetime>
+ <initial_contact>on</initial_contact>
+ <passive>off</passive>
+ <proposal_check>obey</proposal_check>
+ <nat_traversal>off</nat_traversal>
+ <generate_policy>off</generate_policy>
+ <proposal>
+ <encryption_algorithm>3des</encryption_algorithm>
+ <hash_algorithm>md5</hash_algorithm>
+ <authentication_method>pre_shared_key</authentication_method>
+ <dh_group>5</dh_group>
+ </proposal>
+ </remote>
+ <sainfo id="0" enable="true">
+ <src>address 192.168.0.0/24 any</src>
+ <dst>address 192.168.2.0/24 any</dst>
+ <pfs_group>5</pfs_group>
+ <lifetime>time 3600 sec</lifetime>
+ <encryption_algorithm>3des</encryption_algorithm>
+ <authentication_algorithm>hmac_md5</authentication_algorithm>
+ <compression_algorithm>deflate</compression_algorithm>
+ </sainfo>
+ <setkey>
+ <line>spdadd 192.168.0.0/24 192.168.2.0/24 any -P out ipsec esp/tunnel/10.0.0.1-10.0.0.2/use</line>
+ <line>spdadd 192.168.2.0/24 192.168.0.0/24 any -P in ipsec esp/tunnel/10.0.0.2-10.0.0.1/use</line>
+ <setkey>
+</ipsec -->
+
+
+$$$code:conf_table("IPSec", "IPSec link configuration", "ipsec.remote[1]",
+{
+ { label = "Enabled", type = "attr", htmltype = "checkbox", node = ":enable" },
+ { label = "Gateway", type = "node", htmltype = "text", node = "gateway" },
+ { label = "Exchange Mode", type = "node", htmltype = "text", node = "exchange_mode" },
+ { label = "My ID", type = "node", htmltype = "text", node = "my_identifier" },
+ { label = "Peer ID", type = "node", htmltype = "text", node = "peers_identifier" },
+ { label = "Lifetime", type = "node", htmltype = "text", node = "lifetime" },
+ { label = "Initial Contact", type = "node", htmltype = "text", node = "initial_contact" },
+ { label = "Passive", type = "node", htmltype = "text", node = "passive" },
+ { label = "Proposal Check", type = "node", htmltype = "text", node = "proposal_check" },
+ { label = "NAT Traversal", type = "node", htmltype = "text", node = "nat_traversal" },
+ { label = "Generate Policy", type = "node", htmltype = "text", node = "generate_policy" },
+})$$$
+$$$code:conf_table("IPSecProposal", "IPSec link1 proposal configuration", "ipsec.remote[1].proposal",
+{
+ { label = "Encryption Algorithm", type = "node", htmltype = "text", node = "encryption_algorithm" },
+ { label = "HASH Algorithm", type = "node", htmltype = "text", node = "hash_algorithm" },
+ { label = "DH Group", type = "node", htmltype = "text", node = "dh_group" },
+ { label = "Pre Shared Key", type = "node", htmltype = "text", node = "psk" },
+})$$$
+
+$$$code:conf_table("IPSecTunnel", "IPSec link1 Tunnel configuration", "ipsec.sainfo[1]",
+{
+ { label = "Source Address", type = "node", htmltype = "text", node = "src" },
+ { label = "Destination Address", type = "node", htmltype = "text", node = "dst" },
+ { label = "PFS Group", type = "node", htmltype = "text", node = "pfs_group" },
+ { label = "Lifetime", type = "node", htmltype = "text", node = "lifetime" },
+ { label = "Encryption Algorithm", type = "node", htmltype = "text", node = "encryption_algorithm" },
+ { label = "Auth Algorithm", type = "node", htmltype = "text", node = "authentication_algorithm"},
+ { label = "Compression Algorithm", type = "node", htmltype = "text", node = "compression_algorithm" },
+})$$$
+
+$$$code:conf_table("SPD", "IPSec Policy (setkey) configuration", "ipsec.setkey",
+{
+ { label = "Line1", type = "node", htmltype = "text", node = "line[1]"},
+ { label = "Line2", type = "node", htmltype = "text", node = "line[2]"},
+ { label = "Line3", type = "node", htmltype = "text", node = "line[3]"},
+ { label = "Line4", type = "node", htmltype = "text", node = "line[4]"},
+})$$$
+
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Security.OpenVPN.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Security.OpenVPN.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,9 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>OpenVPN configuration</h1>
+
+ Empty
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/Security.SSH.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/Security.SSH.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,9 @@
+$$$code:inc("htdocs/header.html")$$$
+ <h1>SSH tunnels configuration</h1>
+
+ Empty
+
+$$$code:inc("htdocs/footer.html")$$$
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/cmd.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/cmd.xml Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,125 @@
+function process()
+
+ if rq.POST["cmd"] == "get" then
+
+ return (c:getNode(rq.POST["key"]):value());
+
+ elseif rq.POST["cmd"] == "set" then
+
+ c:getNode(rq.POST["key"]):value(rq.POST["value"]);
+ return (c:getNode(rq.POST["key"]):value());
+
+ elseif rq.POST["cmd"] == "upload_config" then
+
+ print(tdump(rq.POST));
+ return ("OK");
+
+ elseif rq.POST["cmd"] == "upgrade" then
+
+ os.execute("LAST=`fetch -o - " .. c:getNode("info.firmware.update_url"):value() .."` ; /etc/upgrade ${LAST} > /dev/console 2>&1");
+ return ("OK");
+
+ elseif rq.POST["cmd"] == "setmany" then
+
+ path = rq.POST["path"];
+ if not path then
+ return ("path missing");
+ end
+ -- print(rq.RequestBody);
+
+ -- if name like "sm:key" do c:getNode(path .. "key"):value(rq.POST["value"]);
+ -- if name like "smattr:key:attr" do c:getNode(path .. "key"):attr("attr", rq.POST["value"]);
+ for k,v in pairs(rq.POST) do
+ attr, _, subpath, attrname = string.find(k, "^smattr:(.-):(.*)");
+ if not v then v = ""; end
+ if (attr) then
+ if string.len(subpath) > 0 then
+ subpath = path .. "." .. subpath;
+ else
+ subpath = path;
+ end
+
+ local n = c:getOrCreateNode(subpath);
+ if not n then
+ print ("ERROR: can't find/create node \"" .. subpath .. "\"");
+ return ("ERROR: can't find/create node \"" .. subpath .. "\"");
+ end
+ n:attr(attrname, v);
+ print(subpath .." ".. attrname .. " newval=" .. c:getNode(subpath):attr(attrname));
+ elseif string.find(k, "^sm:") then
+ _, _, subpath = string.find(k, "^sm:(.*)");
+ if string.len(subpath) > 0 then
+ subpath = path .. "." .. subpath;
+ else
+ subpath = path;
+ end
+ local n = c:getOrCreateNode(subpath);
+ if not n then
+ print ("ERROR: can't find/create node \"" .. subpath .. "\"");
+ return ("ERROR: can't find/create node \"" .. subpath .. "\"");
+ end
+ n:value(v or "");
+ print(subpath .. " newval=" .. n:value());
+ end
+ end
+ return ("OK");
+
+ elseif rq.POST["save"] == "config" then
+
+ print("Saving configuration to config.xml");
+ if not save_file("config.xml", xmldump(c:gettree())) then
+ return ("Error saving configuration");
+ end
+ if os.execute("/etc/rc.save_config") ~= 0 then
+ return ("Error saving configuration block to flash");
+ end
+ return ("Configuration saved successful");
+
+ elseif rq.POST["restore"] == "config" then
+
+ print("Restoring factory default setting");
+ os.execute("echo '(sleep 5 ; rm /tmp/etc/www/config.xml ; /etc/rc.save_config ; /sbin/reboot ) & ' >> /tmp/restore_scrip.sh");
+ if os.execute("sh /tmp/restore_scrip.sh &") ~= 0 then
+ return ("Run restore script fail");
+ end
+ return ("Configuration restore procedure started");
+
+ elseif rq.POST["system"] == "reboot" then
+
+ print("Reboot device");
+ os.execute("echo '(sleep 5 ; /sbin/reboot) &' > /tmp/reboot_scrip.sh");
+ os.execute("echo 'Run /tmp/reboot_scrip.sh' > /dev/console");
+ if os.execute("sh /tmp/reboot_scrip.sh &") ~= 0 then
+ return ("Can't execute reboot script");
+ end
+ os.execute("echo 'Return \"Reboot in progress\" to parent' > /dev/console");
+ return ("Reboot in progress");
+
+ elseif rq.POST["telnet"] == "enable" then
+
+ print("Enabling telnet service");
+ os.execute("echo 'Enabling telnet service' > /dev/console");
+ os.execute("/usr/libexec/telnetd -4 -debug 23 &");
+ return ("telnet service started");
+
+ else
+
+-- print(tdump(rq));
+-- print(tdump(rq.POST));
+ return ("Unknow command");
+
+ end
+end
+
+
+
+ return ([[
+<?xml version="1.0" encoding="utf-8" ?>
+<data>
+]] ..
+process() ..
+[[
+</data>
+]]);
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/config.dat
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/config.dat Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,10 @@
+
+
+if rq.POST["cmd"] == "download_config" then
+ return (xmldump(c:gettree()));
+else
+ return ("Unknow command");
+end
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/css/anim.css
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/css/anim.css Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,131 @@
+/* color and iteration examples */
+a.boxitem {
+ background:#8dd5e7;
+ border:1px solid #004c6d;
+ color:#004c6d;
+ display:block;
+ height:2em;
+ line-height:2em;
+ width:6em;
+ text-align:center;
+}
+
+/* xy and curve examples */
+span.boxitem {
+ background:#ffa928;
+ display:block;
+ height:10px;
+ width:10px;
+}
+
+/* module examples */
+div.boxitem {
+ /*width:34em;*/
+ width:100%;
+ overflow:hidden;
+}
+
+div.boxitem {
+ border-bottom:1px solid #7a97bb;
+}
+
+div.boxitem .yui3-hd {
+ background: url(../img/tool_bar.jpg) repeat-x;
+ cursor:pointer;
+ cursor:hand;
+ /*border:1px solid #243356;*/
+ border:0;
+ zoom:1;
+}
+
+div.boxitem .yui3-hd h4 {
+ border:0;
+ color:#fff;
+ margin:0;
+}
+
+div.boxitem .yui3-bd {
+ background:#abceff;
+ border:solid #7a97bb;
+ border-width:0 1px;
+ clear: both;
+ overflow:hidden;
+ zoom:1;
+}
+
+div.boxitem .yui3-hd,
+div.boxitem .yui3-bd p {
+ margin:0;
+ padding:0.1em 1em;
+}
+
+div.boxitem div.yui3-bd p {
+ margin:0.3em 10px 0 0; /* right margin for scrollbar space */
+}
+
+div.boxitem .yui3-bd p em {
+ font-weight:bold;
+}
+
+/* basic example */
+div.boxitem a.yui3-remove {
+ background-position:0 -300px;
+ height:16px;
+ width:26px;
+}
+
+/* scroll example */
+.boxitem.yui3-scroll {
+ position: relative;
+}
+
+.yui3-scroll .yui3-hd {
+ position: relative;
+}
+.yui3-scroll .yui3-bd {
+ height:10em;
+ overflow:hidden;
+}
+
+.boxitem .yui3-hd .yui3-scroll-controls { /* fake scrollbar */
+ background:#dfdfdf;
+ border-left:1px solid #7a97bb;
+ height:10em;
+ width:13px;
+ position:absolute;
+ right:0;
+ bottom:-10.1em;
+ overflow:hidden;
+}
+
+.boxitem .yui3-hd .yui3-scroll-controls a {
+ margin: 0;
+ position:absolute;
+ top:0;
+ right:0;
+ height:14px;
+ width:14px;
+ Xborder:1px solid #000;
+}
+
+.boxitem .yui3-scroll-controls a.yui3-scrollup {
+ background-position:-12px -752px; /* scroll up icon */
+}
+
+.boxitem .yui3-scroll-controls a.yui3-scrolldown {
+ background-position:-12px -804px; /* scroll down icon */
+ top:auto;
+ bottom:0;
+}
+
+/* reverse and easing examples */
+.boxitem a.yui3-toggle {
+ background-position:0 -400px; /* close (minus) icon */
+ height:15px;
+ width:15px;
+}
+
+.boxitem
+.yui3-closed a.yui3-toggle {
+ background-position:0 -350px; /* open (plus) icon */
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/css/router.css
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/css/router.css Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,290 @@
+html, div, h1, h2, h3, h4, p, ul, ol, li, dl, dt, dd, td, input, select, textarea
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+}
+
+body
+{
+ background: #CCDCE2;
+ font-size: 12px; font-family:
+ Arial; margin: 0px;
+}
+
+body.body_fw{
+ background: #ffffff;
+}
+
+input, select, textarea
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 11px;
+}
+
+input.text
+{
+ text-align: left;
+ border: solid;
+ border-width: 1px;
+ border-color: steelblue;
+}
+
+.style6
+{
+ font-size: 14px;
+ font-weight: bold;
+}
+.r_tb
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ text-align:right;
+}
+.c_tb
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ text-align:center;
+}
+.l_tb
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ text-align:left;
+}
+.br_tb
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ text-align:right;
+ font-weight: bold;
+}
+.bc_tb
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ text-align:center;
+ font-weight: bold;
+}
+.bl_tb
+{
+ font-family: Tahoma, Helvetica, Geneva, Arial, sans-serif;
+ font-size: 12px;
+ text-align:left;
+ font-weight: bold;
+}
+
+h1
+{
+ color: #000000;
+ font-size: 12px;
+ font-weight: bold;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ margin: 0 -10px 5px -10px;
+ padding: 5px 5px 5px 10px;
+ background: url(img/light_blue1.jpg);
+}
+
+#table_tree{
+ font-family: Arial;
+ font-size: 22px;
+ height: 514px;
+ width: 200px;
+ margin: 5px 4px 3px 1px;
+ border-top-color:#808080;
+ border-left-color:#808080;
+ background:#FFFFFF;
+}
+
+#table_page{
+ width:555px;
+ height: 514px;
+ margin: 5px 5px 5px 3px;
+ border-width: 2px;
+ border-top:solid 2 #ffffff;
+ border-bottom:solid 2 #808080;
+ border-left:solid 2 #ffffff;
+ border-right:solid 2 #808080;
+ background:#CCDCE2;
+}
+
+#table_frame{
+ width:547px;
+ height: 504px;
+ margin: 2px 2px 2px 3px;
+ border: 1px solid #136393;
+ background:#E4EAEB;
+}
+
+#alink_tree a:link, #alink_tree a:visited, #alink_tree a:active{
+ text-decoration: none;
+ font-size: 11px;
+ color: #000000;
+}
+
+#td_header
+{
+ font-family: Arial;
+ height: 30px;
+ color: #000000;
+ font-size: 18px;
+ background: url(img/light_blue1.jpg);
+ padding-left: 15px;
+}
+
+#table_header{
+ height: 30px;
+ width: 100%;
+ background:#CCDCE2;
+}
+
+#table_set_main{
+ width: 100%;
+ margin-top: 1px;
+ border-top: solid 1px #136393;
+ background: #E4EAEB;
+ padding-left: 5px;
+ padding-top: 5px;
+}
+
+#td_left{
+ font-family: Arial;
+ text-align:left;
+ margin: 2px;
+ height:25px;
+}
+
+#td_right{
+ font-family: Arial;
+ text-align:left;
+}
+
+span.word{
+ vertical-align: 3px;
+ padding: 0px 3px 0px 3px;
+}
+
+span.img{
+ vertical-align: 5px;
+}
+
+a.logout{
+ font-family: Arial;
+ font-size: 11px;
+ margin: 0px 0px 0px 0px;
+ padding: 6px 8px 6px 8px;
+ width:200px;
+}
+
+a.logout:link, a.logout:visited, a.logout:active{
+ color: #000000;
+ background: #FFFFCC;
+}
+
+a.logout:hover {
+ color: #0000FF;
+ background: #FFFFCC;
+ text-decoration: underline;
+}
+
+.list_head{
+ background: #4D4D4D;
+ color: #FFFFFF;
+}
+
+.div_tab {
+ background: #ffffff;
+ border-color: #c0c0c0 #ffffff #ffffff #c0c0c0;
+ border-style: inset;
+ border-width: 2px;
+ overflow: auto;
+ height: 125px;
+}
+
+.div_tab td{
+ height: 20px;
+}
+
+.div_tab tr{
+ height: auto;
+}
+
+.div_client_tab{
+ background: #E4EAEB;
+ border-color: #c0c0c0 #ffffff #ffffff #c0c0c0;
+ border-style: inset;
+ border-width: 1px;
+ overflow: auto;
+}
+
+.div_client_tab td{
+ height: 20px;
+}
+
+.div_client_tab tr{
+ height: auto;
+}
+
+.table_tool{
+ width: 99%;
+ background: #E4EAEB;
+ border: 1px solid #136393;
+
+}
+
+.table_tool_td{
+ font-family: Arial;
+ height: 25px;
+ color: #ffffff;
+ font-size: 15px;
+ background: #6595b9;
+ padding-left: 5px;
+}
+
+.table_tool td{
+ padding: 3px;
+}
+
+.sec_n {
+ background-color: #EEEEEE;
+ color: #000000;
+ border-left: 1px solid #FFFFFF;
+ border-top: 1px solid #FFFFFF;
+ border-right: 1px solid gray;
+ border-bottom: 1px solid #FFFFFF
+}
+
+.sec_s {
+ background-color: #D4D0C8;
+ color: #000000;
+ border-left: 1px solid #FFFFFF;
+ border-top: 1px solid #FFFFFF;
+ border-right: 1px solid gray;
+ font-weight: bold;
+}
+
+.TabPane_body {
+ background-color: #D4D0C8;
+ color: #000000;
+ border-left:1px solid #FFFFFF;
+ border-right: 1px solid gray;
+ border-bottom: 1px solid gray;
+ width:99%;
+ height:350px;
+}
+
+.edit_vlan_table{
+
+ background-color: #E4EAEB;
+ margin:20px 10px 0px 10px;
+ border: 1px solid #136393;
+}
+
+.help_title_td
+{
+ font-size: 14px;
+ text-decoration: underline;
+ font-weight:bold;
+
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/event.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/event.xml Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,108 @@
+-- rq = {};
+-- rq.GET = {};
+
+-- rq.GET["cmd" ] = "event";
+-- rq.GET["gw" ] = "192.168.1.3";
+-- rq.GET["dns2" ] = "192.168.1.3";
+-- rq.GET["dns1" ] = "192.168.1.3";
+-- rq.GET["iface" ] = "PPP";
+-- rq.GET["state"] = "up";
+
+-- r = {};
+
+-- function doit()
+
+function process()
+ if not c then
+ print("Configuration structure 'c' is missing");
+ end
+ if not rq then
+ print("Request structure 'rq' is missing");
+ end
+
+ if rq.GET["cmd"] == "get" then
+
+ return (c:getNode(rq.GET["key"]):value());
+
+ elseif rq.GET["cmd"] == "set" then
+
+ c:getNode(rq.GET["key"]):value(rq.GET["value"]);
+ return (c:getNode(rq.GET["key"]):value());
+
+ elseif rq.GET["restore"] == "config" then
+
+ os.execute("echo \"event.xml: " .. rq.QueryString .."\" > /dev/console");
+ if os.execute("rm /tmp/etc/www/config.xml") ~= 0 then
+ return ("Can't remove current config");
+ end
+ if os.execute("/etc/rc.save_config") ~= 0 then
+ return ("Error saving configuration block to flash");
+ end
+ if os.execute("reboot &") ~= 0 then
+ return ("Error when trying reboot");
+ end
+ return ("Configuration restored successful");
+
+ elseif rq.GET["cmd"] == "event" then
+ -- print(rq.RequestHeader);
+ -- cmd=event&iface=wan0&state=linkup
+ local iface = rq.GET["iface"];
+ local newstate = rq.GET["state"];
+
+ if not iface then
+ return ("event.lua: ERROR: Interface not defined");
+ end
+
+ if type(r[iface]) ~= "table" then r[iface] = {}; end
+
+ print("echo \"event.xml: " .. rq.QueryString .."\" > /dev/console");
+ if newstate == "up" then
+ -- Update NAT alias address for Static/DHCP
+ if iface == "wan0" then
+ local ip = rq.GET["ip"];
+ ip = ip:gsub("/%d+", "");
+ os.execute("ngctl msg wan0nat: setaliasaddr " .. ip);
+ end
+ elseif newstate == "linkup" then
+ --
+ run_dhclient(c, iface); -- if DHCP enabled.
+ elseif newstate == "down" then
+ --
+ elseif newstate == "linkdown" then
+ --
+ end
+
+ for k,v in pairs(rq.GET) do
+ if (k ~= "iface") and (k ~= "cmd") then
+ r[iface][k] = v;
+ end
+ end
+
+ return "OK";
+
+ elseif rq.GET["cmd"] == "revent" then
+
+ iface = rq.GET["iface"];
+
+ if r[iface] then
+ return (tdump(r[iface]));
+ else
+ return ("ERROR: no data for interface " .. iface);
+ end
+ else
+ return ("ERROR: unknown command");
+ end
+end
+
+return ([[
+<?xml version="1.0" encoding="utf-8" ?>
+<data>]] ..
+process() ..
+[[
+</data>
+]]);
+
+-- end
+
+-- print(doit());
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/footer.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/footer.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,2 @@
+</body>
+</html>
\ No newline at end of file
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/header.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/header.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title></title>
+ <style type="text/css"> body { margin:0; padding:0; } </style>
+ <link href="css/anim.css" rel="stylesheet" type="text/css">
+ </head>
+ <body class="yui3-skin-sam yui-skin-sam">
+<script type="text/javascript" src="js/ajax.js"></script>
+<script>
+function send_update(form, proc)
+{
+ var query = getValuesAsArray(form);
+ if (!proc) {
+ proc = function (x) { };
+ }
+ ajax("POST", "/cmd.xml", query, true, proc);
+
+ return false;
+}
+</script>
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/home_sys.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/home_sys.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+
+<HTML XMLNS="http://www.w3.org/1999/xhtml">
+ <HEAD>
+ <LINK REL="stylesheet" HREF="index_files/router.css" TYPE="text/css">
+ <META http-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
+ <TITLE>$$$info.device.vendor$$$ $$$info.device.model$$$ $$$info.device.revision$$$</TITLE>
+ <script type="text/javascript" src="js/utils.js"></script>
+ <script type="text/javascript" src="js/ajax.js"></script>
+ </HEAD>
+ <BODY LEFTMARGIN="0" TOPMARGIN="0" STYLE="overflow:auto;" BGCOLOR="#ccdce2" MARGINHEIGHT="0" MARGINWIDTH="0">
+ <TABLE ID="table_frame" BORDER="0" CELLPADDING="0" CELLSPACING="0">
+ <TBODY>
+ <TR>
+ <TD VALIGN="top">
+ <TABLE ID="table_header" CELLPADDING="0" CELLSPACING="0">
+ <TBODY>
+ <TR><TD ID="td_header" VALIGN="middle">System Information</TD></TR>
+ </TBODY>
+ </TABLE>
+ <TABLE ID="table_set_main" BORDER="0" CELLPADDING="0" CELLSPACING="0">
+ <!-- ________________________________ Main Content Start ______________________________ -->
+ <TBODY>
+ <TR><TD ID="td_left" HEIGHT="25" WIDTH="150">Device</TD>
+ <TD ID="td_right">$$$info.device.vendor$$$ $$$info.device.model$$$ $$$info.device.revision$$$</TD>
+ </TR>
+ <TR><TD ID="td_left" HEIGHT="25" WIDTH="150">SoC</TD>
+ <TD ID="td_right">$$$info.soc.vendor$$$ $$$info.soc.model$$$ $$$info.soc.revision$$$</TD>
+ </TR>
+ <TR><TD ID="td_left" HEIGHT="25">Firmware Version</TD><TD ID="td_right">$$$info.firmware.version$$$</TD></TR>
+ <TR><TD ID="td_left" HEIGHT="25">Code revision</TD><TD ID="td_right">$$$code: r.zrouter_version.revision $$$</TD></TR>
+ <TR><TD ID="td_left" HEIGHT="25">Firmware build date</TD><TD ID="td_right">$$$code: r.zrouter_version.build $$$</TD></TR>
+ <TR><TD ID="td_left" HEIGHT="25">System Name</TD><TD ID="td_right">$$$info.hostname$$$</TD></TR>
+ <TR><TD ID="td_left" HEIGHT="25">Location</TD><TD ID="td_right">$$$info.location$$$</TD></TR>
+ <TR><TD ID="td_left" HEIGHT="25">System Time</TD><TD ID="td_right">$$$code:os.date("%Y-%m-%d %H:%M:%S")$$$</TD></TR>
+ <!--TR><TD ID="td_left" HEIGHT="25">Up Time</TD><TD ID="td_right"></TD></TR-->
+ <!-- TR><TD ID="td_left" HEIGHT="25">Operation Mode</TD><TD ID="td_right">Access Point</TD></TR -->
+ <!-- TR><TD ID="td_left" HEIGHT="25">MAC Address</TD><TD ID="td_right">00:21:91:5a:86:f2</TD></TR-->
+ <!-- TR><TD ID="td_left" HEIGHT="25">SSID 1~3</TD><TD ID="td_right">02:21:91:5a:86:f2 ~ 06:21:91:5a:86:f2</TD></TR-->
+ <TR><TD ID="td_left" HEIGHT="25">IP Address</TD><TD ID="td_right">$$$interfaces.bridge0.ipaddr$$$</TD></TR>
+
+ </TBODY>
+ <!-- ________________________________ Main Content End _______________________________ -->
+ </TABLE>
+ </TD>
+ </TR>
+ </TBODY>
+ </TABLE>
+ </BODY>
+</HTML>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/FreeBSD_logo.png
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/FreeBSD_logo.png has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/banner.jpg
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/banner.jpg has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/config.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/config.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/folder.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/folder.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/help.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/help.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/home.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/home.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/join.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/join.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/joinbottom.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/joinbottom.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/line.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/line.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/logout.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/logout.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/minus.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/minus.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/minusbottom.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/minusbottom.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/monitor.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/monitor.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/open_file.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/open_file.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/open_folder.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/open_folder.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/plus.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/plus.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/plusbottom.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/plusbottom.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/sys.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/sys.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/text.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/text.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/themespacer.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/themespacer.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/tool.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/tool.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar.jpg
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar.jpg has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar_v.jpg
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/tool_bar_v.jpg has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/img/triangle.gif
Binary file profiles/lua_web_ui/files/etc/www/htdocs/img/triangle.gif has changed
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/index.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/index.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,102 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <link rel="stylesheet" href="css/router.css" type="text/css" />
+ <link rel="stylesheet" href="css/toolbar.css" type="text/css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+ <title>$$$info.device.vendor$$$ $$$info.device.model$$$ $$$info.device.revision$$$</title>
+ <script type="text/javascript" src="js/utils.js"></script>
+ <script type="text/javascript" src="js/wizard.js"></script>
+ <!-- script type="text/javascript" src="js/tree.js"></script -->
+ <script type="text/javascript" src="js/view.js"></script>
+ <script type="text/javascript" src="js/ajax.js"></script>
+</head>
+<body leftmargin="0" topmargin="0" style="overflow: auto;" bgcolor="#ccdce2" marginheight="0" marginwidth="0">
+ <center>
+ <table id="MainTable" border="1" bordercolor="#1e4c7d" cellpadding="0" cellspacing="0">
+ <tbody>
+ <tr>
+ <td colspan="2">
+ <table background="img/banner.jpg" border="0" cellpadding="0" cellspacing="0" height="71" width="1000">
+ <tbody>
+ <tr>
+ <td align="right" valign="middle">
+ <font style="color: white; font-family: Arial; font-style: normal; font-variant: normal; font-weight: normal; font-size: 12pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">
+ <b>$$$info.device.vendor$$$ $$$info.device.model$$$ $$$info.device.revision$$$</b>
+ </font>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <div class='toolbar'>
+ <ul>
+ <li><a href='home_sys.html' target='ifrMain'><span>Home<img src='img/home.gif' width='16' border='0' hspace='10'></span></a></li>
+ <li class='separator'> </li>
+ <li><a href='#'><span>Maintenance<img src='img/tool.gif' width='16' border='0' hspace='10'></span></a>
+ <ul>
+ <li><a href='#' onClick="tryget('system=reboot'); return false;"><span>Reboot</span></a></li>
+ </ul>
+ </li>
+ <li class='separator'> </li>
+ <li><a href='#'><span>Configuration</span></a>
+ <ul>
+ <li><a href='#' onClick="tryget('save=config'); return false;"><span>Save Configuration</span></a></li>
+ <li><a href='#' onClick="tryget('restore=config'); return false;"><span>Restore to Default</span></a></li>
+ <li><a href='#' onClick="tryget('telnet=enable'); return false;"><span>Run telnet service</span></a></li>
+ </ul>
+ </li>
+ <li class='separator'> </li>
+ <li><a href='http://www.dlink.ua/files/products/ftp/pub/Router/DIR-632/Help/'><span>Help</span></a></li>
+ </ul>
+ </div>
+ <div style="clear:both; height: 0px; margin: 0px 0px 0px 0px;"> </div>
+ </td>
+ </tr>
+
+
+ <tr>
+ <td bordercolor="ccdce2" valign="top">
+ <table id="table_tree" style="margin: 3px; width: 256px;" border="1" cellpadding="0" cellspacing="0" frame="box" width="261">
+ <tbody>
+ <tr>
+ <td id="link_tree" valign="top">
+ <iframe id="ifrMenu" class="ifrMenu" src="tv.html" frameborder="0" height="100%" scrolling="no" width="100%"></iframe>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ <td bordercolor="ccdce2" valign="top" style="padding: 5px;">
+ <table id="table_page" style="margin: 3px; width: 720px; padding: 5px;" border="0" cellpadding="0" cellspacing="0" frame="box" width="750">
+ <tbody>
+ <tr>
+ <td>
+ <iframe id="ifrMain" name="ifrMain" src="home_sys.html" onload="" frameborder="0" height="100%" scrolling="auto" width="100%"></iframe>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table background="img/FreeBSD_logo.png" border="0" cellpadding="0" cellspacing="0" height="75" width="1000">
+ <tbody>
+ <tr>
+ <td align="right" valign="middle">
+
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </center>
+</body>
+</html>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/ajax.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/ajax.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,107 @@
+
+function getXmlHttp()
+{
+ var xmlhttp;
+ try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
+ catch (e) {
+ try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP.6.0"); }
+ catch (E) { }
+ try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP.3.0"); }
+ catch (E) { }
+ try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
+ catch (E) { xmlhttp = false; }
+ }
+ if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
+ xmlhttp = new XMLHttpRequest();
+ }
+ return xmlhttp;
+}
+
+var xmlhttp = getXmlHttp()
+var xmlhttptimeout = 0;
+
+function ajax(method, target, msg, async, handler)
+{
+
+ if (handler != "ignore") {
+ xmlhttptimeout = setTimeout( function(){ xmlhttp.abort(); alert("Timeout") }, 10000);
+ }
+
+ xmlhttp.onreadystatechange = function()
+ {
+ if (xmlhttp.readyState != 4) return;
+
+ clearTimeout(xmlhttptimeout);
+
+ if (xmlhttp.status == 200) {
+ handler(xmlhttp);
+ } else {
+ alert("Error: " + xmlhttp.statusText);
+ }
+ }
+
+ xmlhttp.open(method, target, async);
+ xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
+ xmlhttp.send(msg);
+}
+
+function getValuesAsArray(formRef)
+{
+ var ret = "r=" + encodeURIComponent(Math.random());
+ var els = formRef.elements;
+ for(var no=0; no < els.length; no++)
+ {
+ if(els[no].disabled)
+ continue;
+ var tag = els[no].tagName.toLowerCase();
+
+ switch(tag){
+ case "input":
+ var type = els[no].type.toLowerCase();
+
+ if(!type)
+ type='text';
+
+ switch(type){
+ case "text":
+ case "image":
+ case "hidden":
+ case "password":
+ ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(els[no].value);
+ break;
+ case "checkbox":
+ if(els[no].checked)
+ ret += '&' + encodeURIComponent(els[no].name) + '=true';
+ else
+ ret += '&' + encodeURIComponent(els[no].name) + '=false';
+ break;
+ case "radio":
+ if(els[no].checked)
+ ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(els[no].value);
+ break;
+ }
+ break;
+ case "select":
+ var string = '';
+ var mult = els[no].getAttribute('multiple');
+ if(mult || mult===''){
+ ops = els[no].options;
+
+ for(var no2=0;no2<ops.length;no2++)
+ {
+ var index = retArray[els[no].name].length;
+ if(ops[no2].selected)
+ ret += '&' + encodeURIComponent(els[no].name + index) + '=' + encodeURIComponent(ops[no2].value);
+ }
+ }else{
+ ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(ops[els[no].selectedIndex].value);
+ }
+ break;
+ case "textarea":
+ ret += '&' + encodeURIComponent(els[no].name) + '=' + encodeURIComponent(els[no].value);
+ break;
+ }
+ }
+ return ret;
+}
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/defineMyTree.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/defineMyTree.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,77 @@
+/* You can find instructions for this file here:
+/ http://www.geocities.com/marcelino_martins/ftv2instructions.html
+*/
+
+// Decide if the names are links or just the icons
+var USETEXTLINKS = 1; //replace 0 with 1 for hyperlinks
+
+// Decide if the tree is to start all open or just showing the root folders
+var STARTALLOPEN = 0; //replace 0 with 1 to show the whole tree
+
+var ICONPATH = 'img/';
+
+var deviceType="Router";
+
+var band=0;
+
+
+if(band==0)
+{
+ var x="CfgWLanParam.html?0";
+}
+else
+{
+ var x="CfgWLanParam.html?1";
+}
+
+
+var foldersTree = gHeader(deviceType, "/home_sys.html");
+var aux1, aux2;
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Basic Settings </font>", ""));
+insDoc(aux1, gLnk("R"," Internet", "/Basic.wan.html"));
+insDoc(aux1, gLnk("R"," Wireless", "/Basic.wlan.html"));
+insDoc(aux1, gLnk("R"," LAN", "/Basic.lan.html"));
+insDoc(aux1, gLnk("R"," IPTV", "/Basic.iptv.html"));
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Security Links </font>", ""));
+insDoc(aux1, gLnk("R"," IPSec", "/Security.IPSec.html"));
+insDoc(aux1, gLnk("R"," OpenVPN", "/Security.OpenVPN.html"));
+insDoc(aux1, gLnk("R"," SSH Tunnels", "/Security.SSH.html"));
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Administration </font>", ""));
+insDoc(aux1, gLnk("R"," Device Info", "/Administration.info.html"));
+insDoc(aux1, gLnk("R"," Users", "/Administration.users.html"));
+insDoc(aux1, gLnk("R"," Firmware", "/Administration.firmware.html"));
+
+//aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Advanced Settings </font>", ""));
+//insDoc(aux1, gLnk("R"," Performance", "/home_sys.html?page=adv_perf.html"));
+//insDoc(aux1, gLnk("R"," Multi-SSID", "/home_sys.html?page=adv_mssid.html"));
+//insDoc(aux1, gLnk("R"," VLAN ", "/home_sys.html?page=adv_8021q.html"));
+//insDoc(aux1, gLnk("R"," Instrusion", "/home_sys.html?page=adv_rogue.html"));
+//insDoc(aux1, gLnk("R"," Schedule", "/home_sys.html?page=adv_schedule.html"));
+//insDoc(aux1, gLnk("R"," QOS", "/home_sys.html?page=adv_qos.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2> DHCP Server</font>", ""));
+//insDoc(aux2, gLnk("R"," Dynamic Pool Setting", "/home_sys.html?page=adv_dhcpd.html"));
+//insDoc(aux2, gLnk("R"," Static Pool Setting", "/home_sys.html?page=adv_dhcps.html"));
+//insDoc(aux2, gLnk("R"," Current IP Mapping List", "/home_sys.html?page=adv_dhcpl.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2> Filters</font>", ""));
+//insDoc(aux2, gLnk("R"," Wireless MAC ACL", "/home_sys.html?page=adv_acl.html"));
+//insDoc(aux2, gLnk("R"," WLAN Partition", "/home_sys.html?page=adv_partition.html"));
+
+aux1 = insFld(foldersTree, gFld("<font face=Tahoma size=2> Status</font>", ""));
+insDoc(aux1, gLnk("R"," Device Information", "/status.lua"));
+insDoc(aux1, gLnk("R"," System Log", "/log.lua"));
+//insDoc(aux1, gLnk("R"," Client Information", "/home_sys.html?page=st_info.html"));
+//insDoc(aux1, gLnk("R"," WDS Information", "/home_sys.html?page=st_wds_info.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2> Stats</font>", ""));
+//insDoc(aux2, gLnk("R"," Ethernet", "/home_sys.html?page=st_stats_lan.html"));
+//insDoc(aux2, gLnk("R"," WLAN", "/home_sys.html?page=st_stats_wl.html"));
+
+//aux2 = insFld(aux1, gFld("<font face=Tahoma size=2>Log</font>", ""));
+//insDoc(aux2, gLnk("R"," View Log", "/home_sys.html?page=st_log.html"));
+//insDoc(aux2, gLnk("R"," Log Settings", "/home_sys.html?page=st_logs.html"));
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/tree.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/tree.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,1360 @@
+/******************************************************************
+ Definition of class Folder
+******************************************************************/
+function Header(folderDescription, hreference) /* constructor */
+{
+ /* constant data */
+ this.desc = folderDescription;
+ this.hreference = hreference;
+ this.id = -1;
+ this.navObj = 0;
+ this.iconImg = 0;
+ this.nodeImg = 0;
+ this.isLastNode = 0;
+ this.iconSrc = ICONPATH + "monitor.gif";
+ this.iconSrcClosed = ICONPATH + "monitor.gif";
+ this.children = new Array;
+ this.nChildren = 0;
+ this.level = 0;
+ this.leftSideCoded = "";
+ this.isLastNode=false;
+ this.parentObj = null;
+ this.maySelect=true;
+ this.prependHTML = "";
+
+ /* dynamic data */
+ this.isOpen = false;
+ this.isLastOpenedFolder = false;
+ this.isRendered = 0;
+
+ /* methods */
+ this.initialize = initializeFolder;
+ this.setState = setStateFolder;
+ this.addChild = addChild;
+ this.createIndex = createEntryIndex;
+ this.escondeBlock = escondeBlock;
+ this.esconde = escondeFolder;
+ this.folderMstr = folderMstr;
+ this.renderOb = drawFolder;
+ this.totalHeight = totalHeight;
+ this.subEntries = folderSubEntries;
+ this.linkHTML = linkFolderHTML;
+ this.blockStartHTML = blockStartHTML;
+ this.blockEndHTML = blockEndHTML;
+ this.nodeImageSrc = nodeImageSrc;
+ this.iconImageSrc = iconImageSrc;
+ this.getID = getID;
+ this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders;
+}
+
+function Folder(folderDescription, hreference) /* constructor */
+{
+ /* constant data */
+ this.desc = folderDescription;
+ this.hreference = hreference;
+ this.id = -1;
+ this.navObj = 0;
+ this.iconImg = 0;
+ this.nodeImg = 0;
+ this.isLastNode = 0;
+ this.iconSrc = ICONPATH + "open_folder.gif";
+ this.iconSrcClosed = ICONPATH + "folder.gif";
+ this.children = new Array;
+ this.nChildren = 0;
+ this.level = 0;
+ this.leftSideCoded = "";
+ this.isLastNode=false;
+ this.parentObj = null;
+ this.maySelect=true;
+ this.prependHTML = "";
+
+ /* dynamic data */
+ this.isOpen = false;
+ this.isLastOpenedFolder = false;
+ this.isRendered = 0;
+
+ /* methods */
+ this.initialize = initializeFolder;
+ this.setState = setStateFolder;
+ this.addChild = addChild;
+ this.createIndex = createEntryIndex;
+ this.escondeBlock = escondeBlock;
+ this.esconde = escondeFolder;
+ this.folderMstr = folderMstr;
+ this.renderOb = drawFolder;
+ this.totalHeight = totalHeight;
+ this.subEntries = folderSubEntries;
+ this.linkHTML = linkFolderHTML;
+ this.blockStartHTML = blockStartHTML;
+ this.blockEndHTML = blockEndHTML;
+ this.nodeImageSrc = nodeImageSrc;
+ this.iconImageSrc = iconImageSrc;
+ this.getID = getID;
+ this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders;
+}
+
+function initializeFolder(level, lastNode, leftSide)
+{
+ var j=0;
+ var i=0;
+ nc = this.nChildren;
+
+ this.createIndex();
+ this.level = level;
+ this.leftSideCoded = leftSide;
+
+ if(browserVersion == 0 || STARTALLOPEN==1)
+ this.isOpen=true;
+
+ if(level>0)
+ if(lastNode)
+ /* the last child in the children array */
+ leftSide = leftSide + "0";
+ else
+ leftSide = leftSide + "1";
+
+ this.isLastNode = lastNode;
+
+ if(nc > 0)
+ {
+ level = level + 1;
+ for (i = 0; i < this.nChildren; i++)
+ {
+ if (i == this.nChildren-1)
+ this.children[i].initialize(level, 1, leftSide);
+ else
+ this.children[i].initialize(level, 0, leftSide);
+ }
+ }
+}
+
+function drawFolder(insertAtObj)
+{
+ var nodeName = "";
+ var auxEv = "";
+ var docW = "";
+
+ var leftSide = leftSideHTML(this.leftSideCoded);
+
+ if (browserVersion > 0)
+ auxEv = "<span onClick='clickOnNode(\""+this.getID()+"\")' onMouseOver='showCursor(this);'>";
+ else
+ auxEv = "<span>";
+
+ nodeName = this.nodeImageSrc();
+
+ if (this.level>0)
+ if (this.isLastNode)
+ /* the last child in the children array */
+ leftSide = leftSide + "<td valign=top>" + auxEv +
+ "<img name='nodeIcon" + this.id + "' id='nodeIcon" +
+ this.id + "' src='" + nodeName + "' height=16 border=0></span></td>";
+ else
+ leftSide = leftSide + "<td valign=top background=" + ICONPATH + "line.gif>" + auxEv +
+ "<img name='nodeIcon" + this.id + "' id='nodeIcon" +
+ this.id + "' src='" + nodeName + "' height=16 border=0></span></td>";
+
+ this.isRendered = 1;
+
+ if (browserVersion == 2)
+ {
+ if (!doc.yPos)
+ doc.yPos=20;
+ }
+
+ docW = this.blockStartHTML("folder");
+
+ docW = docW + "<tr>" + leftSide + "<td valign=top>";
+ if (USEICONS)
+ {
+ docW = docW + auxEv;/* this.linkHTML(false) */
+ docW = docW + "<img id='folderIcon" + this.id + "' name='folderIcon" + this.id + "' src='" + this.iconImageSrc() + "' border=0></span>";
+ }
+ else
+ {
+ if (this.prependHTML == "")
+ docW = docW + "<img src=" + ICONPATH + "themespacer.gif height=2 width=2>";
+ }
+
+ if (WRAPTEXT)
+ docW = docW + "</td>"+this.prependHTML+"<td valign=middle width=100%>";
+ else
+ docW = docW + "</td>"+this.prependHTML+"<td valign=middle nowrap width=100%>";
+ if (USETEXTLINKS)
+ {
+ if(this.linkHTML(true)=="<a>" && (this.getID()!=0))
+ docW = docW + auxEv + this.desc + "</span>";
+ else
+ docW = docW + this.linkHTML(true) + this.desc + "</a>";
+ }
+ else
+ docW = docW + auxEv + this.desc + "</span>";
+
+ docW = docW + "</td>";
+ docW = docW + this.blockEndHTML();
+
+ if (insertAtObj == null)
+ {
+ if (supportsDeferral)
+ {
+ doc.write("<div id=domRoot></div>"); /* transition between regular flow HTML, and node-insert DOM DHTML */
+ insertAtObj = getElById("domRoot");
+ insertAtObj.insertAdjacentHTML("beforeEnd", docW);
+ }
+ else
+ doc.write(docW);
+ }
+ else
+ {
+ insertAtObj.insertAdjacentHTML("afterEnd", docW);
+ }
+
+ if (browserVersion == 2)
+ {
+ this.navObj = doc.layers["folder"+this.id];
+ if (USEICONS)
+ this.iconImg = this.navObj.document.images["folderIcon"+this.id]
+ this.nodeImg = this.navObj.document.images["nodeIcon"+this.id];
+ doc.yPos=doc.yPos+this.navObj.clip.height;
+ }
+ else if (browserVersion != 0)
+ {
+ this.navObj = getElById("folder"+this.id);
+ if (USEICONS)
+ this.iconImg = getElById("folderIcon"+this.id);
+ this.nodeImg = getElById("nodeIcon"+this.id);
+ }
+}
+
+function setStateFolder(isOpen)
+{
+ var subEntries;
+ var totalHeight;
+ var fIt = 0;
+ var i=0;
+ var currentOpen;
+
+ if (isOpen == this.isOpen)
+ return;
+
+ if (browserVersion == 2)
+ {
+ totalHeight = 0;
+ for (i=0; i < this.nChildren; i++)
+ totalHeight = totalHeight + this.children[i].navObj.clip.height;
+ subEntries = this.subEntries();
+ if (this.isOpen)
+ totalHeight = 0 - totalHeight;
+ for (fIt = this.id + subEntries + 1; fIt < nEntries; fIt++)
+ indexOfEntries[fIt].navObj.moveBy(0, totalHeight);
+ }
+ this.isOpen = isOpen;
+
+ if (this.getID()!=foldersTree.getID() && PERSERVESTATE && !this.isOpen) /* closing */
+ {
+ currentOpen = GetCookie("clickedFolder");
+ if (currentOpen != null)
+ {
+ currentOpen = currentOpen.replace(this.getID()+cookieCutter, "");
+ SetCookie("clickedFolder", currentOpen);
+ }
+ }
+
+ if (!this.isOpen && this.isLastOpenedfolder)
+ {
+ lastOpenedFolder = null;
+ this.isLastOpenedfolder = false;
+ }
+ propagateChangesInState(this);
+}
+
+function propagateChangesInState(folder)
+{
+ var i=0;
+
+ /* Change icon */
+ if (folder.nChildren > 0 && folder.level>0) /* otherwise the one given at render stays */
+ folder.nodeImg.src = folder.nodeImageSrc();
+
+ /* Change node */
+ if (USEICONS)
+ folder.iconImg.src = folder.iconImageSrc();
+
+ /* Propagate changes */
+ for (i=folder.nChildren-1; i>=0; i--)
+ if (folder.isOpen)
+ folder.children[i].folderMstr(folder.navObj);
+ else
+ folder.children[i].esconde();
+}
+
+function escondeFolder()
+{
+ this.escondeBlock();
+
+ this.setState(0);
+}
+
+function linkFolderHTML(isTextLink)
+{
+ var docW = "";
+
+ if (this.hreference)
+ {
+ if (USEFRAMES)
+ docW = docW + "<a href='" + this.hreference + "' TARGET=\"ifrMain\" ";
+ else
+ docW = docW + "<a href='" + this.hreference + "' TARGET=_top ";
+
+ if (isTextLink)
+ {
+ docW += "id=\"itemTextLink"+this.id+"\" ";
+ }
+
+ if (browserVersion > 0)
+ docW = docW + "onClick='javascript:clickOnFolder(\""+this.getID()+"\")'";
+
+ docW = docW + ">";
+ }
+ else
+ {
+ docW = docW + "<a>";
+ }
+
+ return docW;
+}
+
+function addChild(childNode)
+{
+ this.children[this.nChildren] = childNode;
+ childNode.parentObj = this;
+ this.nChildren++;
+ return childNode;
+}
+
+function folderSubEntries()
+{
+ var i = 0;
+ var se = this.nChildren;
+
+ for (i=0; i < this.nChildren; i++)
+ {
+ if (this.children[i].children) /* is a folder */
+ se = se + this.children[i].subEntries();
+ }
+ return se;
+}
+
+function nodeImageSrc()
+{
+ var srcStr = "";
+ if (this.isLastNode) /* the last child in the children array */
+ {
+ if (this.nChildren == 0)
+ srcStr = ICONPATH + "joinbottom.gif";
+ else if (this.isOpen)
+ srcStr = ICONPATH + "minusbottom.gif";
+ else
+ srcStr = ICONPATH + "plusbottom.gif";
+ }
+ else
+ {
+ if (this.nChildren == 0)
+ srcStr = ICONPATH + "join.gif";
+ else if (this.isOpen)
+ srcStr = ICONPATH + "minus.gif";
+ else
+ srcStr = ICONPATH + "plus.gif";
+ }
+ return srcStr;
+}
+
+function iconImageSrc()
+{
+ if (this.isOpen)
+ return(this.iconSrc);
+ else
+ return(this.iconSrcClosed);
+}
+
+/*
+ * Definition of class Item (a document or link inside a Folder)
+ */
+function Item(itemDescription, itemLink, target) /* Constructor */
+{
+ /* constant data */
+ this.desc = itemDescription;
+ this.link = ""+itemLink;
+ this.id = -1; /* initialized in initalize() */
+ this.navObj = 0 ;/* initialized in render() */
+ this.iconImg = 0; /* initialized in render() */
+ this.iconSrc = ICONPATH + "text.gif";
+ this.isRendered = 0;
+ this.isLastNode = false;
+ this.level = 0;
+ this.leftSideCoded = "";
+ this.nChildren = 0;
+ this.target = target;
+ this.parentObj = null;
+ this.maySelect=true;
+ this.prependHTML = "";
+
+ /* methods */
+ this.initialize = initializeItem;
+ this.createIndex = createEntryIndex;
+ this.escondeBlock = escondeBlock;
+ this.esconde = escondeBlock;
+ this.folderMstr = folderMstr;
+ this.renderOb = drawItem;
+ this.totalHeight = totalHeight;
+ this.blockStartHTML = blockStartHTML;
+ this.blockEndHTML = blockEndHTML;
+ this.getID = getID;
+ this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders;
+}
+
+function initializeItem(level, lastNode, leftSide)
+{
+ this.createIndex();
+ this.level = level;
+ this.leftSideCoded = leftSide;
+ this.isLastNode = lastNode;
+}
+
+function drawItem(insertAtObj)
+{
+ var leftSide = leftSideHTML(this.leftSideCoded);
+ var docW = "";
+
+ /*
+ * In Netscape, it will calling onclick function first and open new window, but it's wrong!
+ * We don't really know this onclick function use for what and remove it!
+ * var fullLink = "href=\""+this.link+"\" target=\""+this.target+"\"
+ * onClick=\"clickOnLink('"+this.getID()+"\', '"+this.link+"','"+this.target+"');return false;\"";
+ */
+ var fullLink = 'href=\"'+this.link+'\" target=\"'+this.target+'\"';
+
+ this.isRendered = 1;
+
+ if (this.level>0)
+ if (this.isLastNode) /* the last 'brother' in the children array */
+ {
+ leftSide = leftSide + "<td valign=top><img src='" + ICONPATH + "joinbottom.gif' height=16 ></td>";
+ }
+ else
+ {
+ leftSide = leftSide + "<td valign=top background=" + ICONPATH + "line.gif><img src='" + ICONPATH + "join.gif' height=16 ></td>";
+ }
+
+ docW = docW + this.blockStartHTML("item");
+
+ docW = docW + "<tr>" + leftSide + "<td valign=top>";
+ if (USEICONS)
+ docW = docW + "<a " + fullLink + " id=\"itemIconLink"+this.id+"\">" +
+ "<img id='itemIcon"+this.id+"' " + "src='"+this.iconSrc+"' border=0>" + "</a>";
+ else if (this.prependHTML == "")
+ docW = docW + "<img src=" + ICONPATH + "themespacer.gif height=2 width=3>";
+
+ if (WRAPTEXT)
+ docW = docW + "</td>"+this.prependHTML+"<td valign=middle width=100%>";
+ else
+ docW = docW + "</td>"+this.prependHTML+"<td valign=middle nowrap width=100%>";
+
+ if (USETEXTLINKS)
+ docW = docW + "<a " + fullLink + " id=\"itemTextLink"+this.id+"\">" + this.desc + "</a>";
+ else
+ docW = docW + this.desc;
+
+ docW = docW + "</td>";
+
+ docW = docW + this.blockEndHTML();
+
+ if (insertAtObj == null)
+ {
+ doc.write(docW);
+ }
+ else
+ {
+ insertAtObj.insertAdjacentHTML("afterEnd", docW);
+ }
+
+ if (browserVersion == 2)
+ {
+ this.navObj = doc.layers["item"+this.id];
+ if (USEICONS)
+ this.iconImg = this.navObj.document.images["itemIcon"+this.id];
+ doc.yPos=doc.yPos+this.navObj.clip.height;
+ }
+ else if (browserVersion != 0)
+ {
+ this.navObj = getElById("item"+this.id);
+ if (USEICONS)
+ this.iconImg = getElById("itemIcon"+this.id);
+ }
+}
+
+
+/*
+ * Methods common to both objects (pseudo-inheritance)
+ */
+function forceOpeningOfAncestorFolders()
+{
+ if (this.parentObj == null || this.parentObj.isOpen)
+ return;
+ else
+ {
+ this.parentObj.forceOpeningOfAncestorFolders();
+ clickOnNodeObj(this.parentObj);
+ }
+}
+
+function escondeBlock()
+{
+ if (browserVersion == 1 || browserVersion == 3)
+ {
+ if (this.navObj.style.display == "none")
+ return;
+ this.navObj.style.display = "none";
+ }
+ else
+ {
+ if (this.navObj.visibility == "hidden")
+ return;
+ this.navObj.visibility = "hidden";
+ }
+}
+
+function folderMstr(domObj)
+{
+ if (browserVersion == 1 || browserVersion == 3)
+ {
+ if (t==-1)
+ return;
+ }
+
+ if (!this.isRendered)
+ this.renderOb(domObj);
+ else if (browserVersion == 1 || browserVersion == 3)
+ this.navObj.style.display = "block";
+ else
+ this.navObj.visibility = "show";
+}
+
+function blockStartHTML(idprefix)
+{
+ var idParam = "id='" + idprefix + this.id + "'";
+ var docW = "";
+
+ if (browserVersion == 2)
+ docW = "<layer "+ idParam + " top=" + doc.yPos + " visibility=show>";
+ else if (browserVersion != 0)
+ docW = "<div " + idParam + " style='display:block; position:block;'>";
+
+ docW = docW + "<table border=0 cellspacing=0 cellpadding=0 width=100% >";
+
+ return docW;
+}
+
+function blockEndHTML()
+{
+ var docW = "";
+
+ docW = "</table>";
+
+ if (browserVersion == 2)
+ docW = docW + "</layer>";
+ else if (browserVersion != 0)
+ docW = docW + "</div>";
+
+ return docW;
+}
+
+function createEntryIndex()
+{
+ this.id = nEntries;
+ indexOfEntries[nEntries] = this;
+ nEntries++;
+}
+
+/*
+ * total height of subEntries open
+ */
+function totalHeight() /* used with browserVersion == 2 */
+{
+ var h = this.navObj.clip.height;
+ var i = 0;
+
+ if (this.isOpen) /* is a folder and _is_ open */
+ for (i=0 ; i < this.nChildren; i++)
+ h = h + this.children[i].totalHeight();
+
+ return h;
+}
+
+
+function leftSideHTML(leftSideCoded)
+{
+ var i;
+ var retStr = "";
+
+ for (i=0; i<leftSideCoded.length; i++)
+ {
+ if (leftSideCoded.charAt(i) == "1")
+ {
+ retStr = retStr + "<td valign=top background=" + ICONPATH + "line.gif><img src='" + ICONPATH + "line.gif' height=16 ></td>";
+ }
+ if (leftSideCoded.charAt(i) == "0")
+ {
+ retStr = retStr + "<td valign=top><img src='" + ICONPATH + "themespacer.gif' height=16 ></td>";
+ }
+ }
+ return retStr;
+}
+
+function getID()
+{
+ /*
+ * define a .xID in all nodes (folders and items) if you want to PERVESTATE that
+ * work when the tree changes. The value eXternal value must be unique for each
+ * node and must node change when other nodes are added or removed
+ * The value may be numeric or string, but cannot have the same char used in cookieCutter */
+ if (typeof this.xID != "undefined")
+ return this.xID;
+ else
+ return this.id;
+}
+
+
+/* Events */
+function clickOnFolder(folderId)
+{
+ var clicked = findObj(folderId);
+
+ if (!clicked.isOpen)
+ {
+ clickOnNodeObj(clicked);
+ }
+
+ if (lastOpenedFolder != null && lastOpenedFolder != folderId)
+ /* sets lastOpenedFolder to null */
+ clickOnNode(lastOpenedFolder);
+ if (clicked.nChildren==0)
+ {
+ lastOpenedFolder = folderId;
+ clicked.isLastOpenedfolder = true;
+ }
+
+ if (isLinked(clicked.hreference))
+ {
+ highlightObjLink(clicked);
+ }
+}
+
+function clickOnNode(folderId)
+{
+ clickOnNodeObj(findObj(folderId));
+}
+
+function clickOnNodeObj(folderObj)
+{
+ var state = 0;
+ var currentOpen;
+
+ if(folderObj.getID() == 0)
+ {
+ state = false; /* Header */
+ }
+ else
+ {
+ state = folderObj.isOpen;
+ }
+
+ folderObj.setState(!state); /* open<->close */
+
+ if (folderObj.id!=foldersTree.id && PERSERVESTATE)
+ {
+ currentOpen = GetCookie("clickedFolder");
+ if (currentOpen == null)
+ currentOpen = "";
+
+ if (!folderObj.isOpen) /* closing */
+ {
+ currentOpen = currentOpen.replace(folderObj.getID()+cookieCutter, "");
+ SetCookie("clickedFolder", currentOpen);
+ }
+ else
+ SetCookie("clickedFolder", currentOpen+folderObj.getID()+cookieCutter);
+ }
+}
+
+function clickOnLink(clickedId, target, windowName)
+{
+ highlightObjLink(findObj(clickedId));
+
+ if (isLinked(target))
+ {
+ window.open(target,windowName);
+ }
+}
+
+function ld()
+{
+ /* return document.links.length-1 original */
+ return 0;
+}
+
+
+/* Auxiliary Functions */
+function findObj(id)
+{
+ var i=0;
+ var nodeObj;
+
+ if (typeof foldersTree.xID != "undefined")
+ {
+ nodeObj = indexOfEntries[i];
+ for(i=0;i<nEntries&&indexOfEntries[i].xID!=id;i++)
+ /* may need optimization */
+ ;
+ id = i;
+ }
+ if (id >= nEntries)
+ return null; /* example: node removed in DB */
+ else
+ return indexOfEntries[id];
+}
+
+function isLinked(hrefText)
+{
+ var result = true;
+ result = (result && hrefText !=null);
+ result = (result && hrefText != '');
+ result = (result && hrefText.indexOf('undefined') < 0);
+ result = (result && hrefText.indexOf('parent.op') < 0);
+ return result;
+}
+
+/* Do highlighting by changing background and foreg. colors of folder or doc text */
+function highlightObjLink(nodeObj)
+{
+ if (!HIGHLIGHT || nodeObj==null || nodeObj.maySelect==false)
+ {
+ /* node deleted in DB */
+ return;
+ }
+
+ if (browserVersion == 1 || browserVersion == 3)
+ {
+ var clickedDOMObj = getElById('itemTextLink'+nodeObj.id);
+ if (clickedDOMObj != null)
+ {
+ if (lastClicked != null)
+ {
+ var prevClickedDOMObj = getElById('itemTextLink'+lastClicked.id);
+ prevClickedDOMObj.style.color=lastClickedColor;
+ prevClickedDOMObj.style.backgroundColor=lastClickedBgColor;
+ }
+
+ lastClickedColor = clickedDOMObj.style.color;
+ lastClickedBgColor = clickedDOMObj.style.backgroundColor;
+ clickedDOMObj.style.color=HIGHLIGHT_COLOR;
+ clickedDOMObj.style.backgroundColor=HIGHLIGHT_BG;
+ }
+ }
+
+ lastClicked = nodeObj;
+ if (PERSERVESTATE)
+ SetCookie('highlightedTreeviewLink', nodeObj.getID());
+}
+
+function gFld(description, hreference)
+{
+ folder = new Folder(description, hreference);
+ return folder;
+}
+
+function gHeader(description, hreference)
+{
+ header = new Header(description, hreference);
+ return header ;
+}
+
+function gLnk(optionFlags, description, linkData)
+{
+ var fullLink = "";
+ var targetFlag = "";
+ var target = "";
+ var protocolFlag = "";
+ var protocol = "";
+
+ if (optionFlags>=0) /* is numeric (old style) or empty (error) */
+ {
+ return oldGLnk(optionFlags, description, linkData);
+ }
+
+ targetFlag = optionFlags.charAt(0);
+ if (targetFlag=="B")
+ target = "_blank";
+ if (targetFlag=="P")
+ target = "_parent";
+ if (targetFlag=="R")
+ target = "ifrMain";
+ if (targetFlag=="S")
+ target = "_self";
+ if (targetFlag=="T")
+ target = "_top";
+
+ if (optionFlags.length > 1)
+ {
+ protocolFlag = optionFlags.charAt(1);
+ if (protocolFlag=="h")
+ protocol = "http://";
+ if (protocolFlag=="s")
+ protocol = "https://";
+ if (protocolFlag=="f")
+ protocol = "ftp://";
+ if (protocolFlag=="m")
+ protocol = "mailto:";
+ }
+
+ fullLink = "'" + protocol + linkData + "' target='" + target + "'";
+
+ linkItem = new Item(description, protocol+linkData, target);
+ return linkItem;
+}
+
+/* Function created Aug 1, 2002 for backwards compatibility purposes */
+function oldGLnk(target, description, linkData)
+{
+ var fullLink = "";
+ /* Backwards compatibility code */
+ if (USEFRAMES)
+ {
+ if (target==0)
+ {
+ fullLink = "'"+linkData+"' target=\"ifrMain\"";
+ }
+ else
+ {
+ if (target==1)
+ fullLink = "'http://"+linkData+"' target=_blank";
+ else if (target==2)
+ fullLink = "'http://"+linkData+"' target=\"ifrMain\"";
+ else
+ fullLink = linkData+" target=\"_top\"";
+ }
+ }
+ else
+ {
+ if (target==0)
+ {
+ fullLink = "'"+linkData+"' target=_top";
+ }
+ else
+ {
+ if (target==1)
+ fullLink = "'http://"+linkData+"' target=_blank";
+ else
+ fullLink = "'http://"+linkData+"' target=_top";
+ }
+ }
+
+ linkItem = new Item(description, fullLink);
+ return linkItem;
+}
+
+function insFld(parentFolder, childFolder)
+{
+ return parentFolder.addChild(childFolder);
+}
+
+function insDoc(parentFolder, document)
+{
+ return parentFolder.addChild(document);
+}
+
+function preLoadIcons()
+{
+ var auxImg;
+ var ICONPATH = "";
+ auxImg = new Image();
+ auxImg.src = ICONPATH + "line.gif";
+ auxImg.src = ICONPATH + "minusbottom.gif";
+ auxImg.src = ICONPATH + "minus.gif";
+ auxImg.src = ICONPATH + "plusbottom.gif";
+ auxImg.src = ICONPATH + "plus.gif";
+ auxImg.src = ICONPATH + "themespacer.gif";
+ auxImg.src = ICONPATH + "joinbottom.gif";
+ auxImg.src = ICONPATH + "join.gif";
+ auxImg.src = ICONPATH + "folder.gif";
+ auxImg.src = ICONPATH + "open_folder.gif";
+ auxImg.src = ICONPATH + "text.gif";
+}
+
+/* Open some folders for initial layout, if necessary */
+function setInitialLayout()
+{
+ if (browserVersion > 0 && !STARTALLOPEN)
+ clickOnNodeObj(foldersTree);
+
+ if (!STARTALLOPEN && (browserVersion > 0) && PERSERVESTATE)
+ PersistentFolderOpening();
+}
+
+/* Used with NS4 and STARTALLOPEN */
+function renderAllTree(nodeObj, parent)
+{
+ var i=0;
+ nodeObj.renderOb(parent);
+ if (supportsDeferral)
+ for (i=nodeObj.nChildren-1; i>=0; i--)
+ renderAllTree(nodeObj.children[i], nodeObj.navObj);
+ else
+ for (i=0 ; i < nodeObj.nChildren; i++)
+ renderAllTree(nodeObj.children[i], null);
+}
+
+function hideWholeTree(nodeObj, hideThisOne, nodeObjMove)
+{
+ var i=0;
+ var heightContained=0;
+ var childrenMove=nodeObjMove;
+
+ if (hideThisOne)
+ nodeObj.escondeBlock();
+
+ if (browserVersion == 2)
+ nodeObj.navObj.moveBy(0, 0-nodeObjMove);
+
+ for (i=0 ; i < nodeObj.nChildren; i++)
+ {
+ heightContainedInChild = hideWholeTree(nodeObj.children[i], true, childrenMove)
+ if (browserVersion == 2)
+ {
+ heightContained = heightContained + heightContainedInChild + nodeObj.children[i].navObj.clip.height;
+ childrenMove = childrenMove + heightContainedInChild;
+ }
+ }
+
+ return heightContained;
+}
+
+/*
+ * Simulating inserAdjacentHTML on NS6
+ * Code by thor at jscript.dk
+ */
+
+if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement)
+{
+ HTMLElement.prototype.insertAdjacentElement = function (where,parsedNode)
+ {
+ switch (where)
+ {
+ case 'beforeBegin':
+ this.parentNode.insertBefore(parsedNode,this)
+ break;
+ case 'afterBegin':
+ this.insertBefore(parsedNode,this.firstChild);
+ break;
+ case 'beforeEnd':
+ this.appendChild(parsedNode);
+ break;
+ case 'afterEnd':
+ if (this.nextSibling)
+ this.parentNode.insertBefore(parsedNode,this.nextSibling);
+ else
+ this.parentNode.appendChild(parsedNode);
+ break;
+ }
+ }
+
+ HTMLElement.prototype.insertAdjacentHTML = function(where,htmlStr)
+ {
+ var r = this.ownerDocument.createRange();
+ r.setStartBefore(this);
+ var parsedHTML = r.createContextualFragment(htmlStr);
+ this.insertAdjacentElement(where,parsedHTML);
+ }
+}
+
+function getElById(idVal)
+{
+ if (document.getElementById != null)
+ return document.getElementById(idVal);
+ if (document.all != null)
+ return document.all[idVal];
+
+ alert("Problem getting element by id");
+ return null;
+}
+
+/* Functions for cookies
+ * Note: THESE FUNCTIONS ARE OPTIONAL. No cookies are used unless
+ * the PERSERVESTATE variable is set to 1 (default 0)
+ * The separator currently in use is ^ (chr 94)
+ */
+
+function PersistentFolderOpening()
+{
+ var stateInCookie;
+ var fldStr="";
+ var fldArr;
+ var fldPos=0;
+ var id;
+ var nodeObj;
+ stateInCookie = GetCookie("clickedFolder");
+ SetCookie('clickedFolder', "");
+ /* at the end of function it will be back, minus null cases */
+
+ if(stateInCookie!=null)
+ {
+ fldArr = stateInCookie.split(cookieCutter);
+ for (fldPos=0; fldPos<fldArr.length; fldPos++)
+ {
+ fldStr=fldArr[fldPos];
+ if (fldStr != "")
+ {
+ nodeObj = findObj(fldStr);
+ if (nodeObj!=null) /* may have been deleted */
+ if (nodeObj.setState)
+ {
+ nodeObj.forceOpeningOfAncestorFolders();
+ clickOnNodeObj(nodeObj);
+ }
+ else
+ alert("Internal id is not pointing to a folder anymore. Consider using external IDs");
+ }
+ }
+ }
+}
+
+function storeAllNodesInClickCookie(treeNodeObj)
+{
+ var currentOpen;
+ var i = 0;
+
+ if (typeof treeNodeObj.setState != "undefined") /* is folder */
+ {
+ currentOpen = GetCookie("clickedFolder");
+ if (currentOpen == null)
+ currentOpen = "";
+
+ if (treeNodeObj.getID() != foldersTree.getID())
+ SetCookie("clickedFolder", currentOpen+treeNodeObj.getID()+cookieCutter);
+
+ for (i=0; i < treeNodeObj.nChildren; i++)
+ storeAllNodesInClickCookie(treeNodeObj.children[i]);
+ }
+}
+
+function CookieBranding(name)
+{
+ if (typeof foldersTree.treeID != "undefined")
+ /* needed for multi-tree sites. make sure treeId does not contain cookieCutter; */
+ return name+foldersTree.treeID;
+ else
+ return name;
+}
+
+function GetCookie(name)
+{
+ name = CookieBranding(name);
+
+ var arg = name + "=";
+ var alen = arg.length;
+ var clen = document.cookie.length;
+ var i = 0;
+
+ while (i < clen)
+ {
+ var j = i + alen;
+ if (document.cookie.substring(i, j) == arg)
+ return getCookieVal (j);
+ i = document.cookie.indexOf(" ", i) + 1;
+ if (i == 0)
+ break;
+ }
+ return null;
+}
+
+function getCookieVal(offset)
+{
+ var endstr = document.cookie.indexOf (";", offset);
+ if (endstr == -1)
+ endstr = document.cookie.length;
+ return unescape(document.cookie.substring(offset, endstr));
+}
+
+function SetCookie(name, value)
+{
+ var argv = SetCookie.arguments;
+ var argc = SetCookie.arguments.length;
+ var expires = (argc > 2) ? argv[2] : null;
+ var domain = (argc > 4) ? argv[4] : null;
+ var secure = (argc > 5) ? argv[5] : false;
+ var path = "/";
+ /* allows the tree to remain open across pages with diff names & paths */
+ name = CookieBranding(name);
+
+ document.cookie = name + "=" + escape (value) +
+ ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
+ ((path == null) ? "" : ("; path=" + path)) +
+ ((domain == null) ? "" : ("; domain=" + domain)) +
+ ((secure == true) ? "; secure" : "");
+}
+
+function ExpireCookie (name)
+{
+ var exp = new Date();
+ exp.setTime (exp.getTime() - 1);
+ var cval = GetCookie (name);
+ name = CookieBranding(name);
+ document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
+}
+
+
+/* To customize the tree, overwrite these variables in the configuration file (demoFramesetNode.js, etc.) */
+var USETEXTLINKS = 0;
+var STARTALLOPEN = 0;
+var USEFRAMES = 1;
+var USEICONS = 1;
+var WRAPTEXT = 0;
+var PERSERVESTATE = 0;
+var ICONPATH = 'img';
+var HIGHLIGHT = 0;
+var HIGHLIGHT_COLOR = 'white';
+var HIGHLIGHT_BG = 'blue';
+var BUILDALL = 0;
+
+
+/* Other variables */
+var lastClicked = null;
+var lastClickedColor;
+var lastClickedBgColor;
+var indexOfEntries = new Array;
+var nEntries = 0;
+var browserVersion = 0;
+var selectedFolder=0;
+var lastOpenedFolder=null;
+var t=5;
+var doc = document;
+var supportsDeferral = false;
+var cookieCutter = '^' ;
+/* You can change this if you need to use ^ in your xID or treeID values */
+doc.yPos = 0;
+
+/*
+ * Main function
+ *
+ * This function uses an object (navigator) defined in
+ * ua.js, imported in the main html page (left frame).
+ */
+function initializeDocument()
+{
+ preLoadIcons();
+ switch(navigator.family)
+ {
+ case 'ie4':
+ /* Simply means IE > 3.x */
+ browserVersion = 1;
+ break;
+ case 'opera':
+ /* opera7 has a good DOM */
+ browserVersion = (navigator.version > 6 ? 1 : 0);
+ break;
+ case 'nn4':
+ /* NS4.x */
+ browserVersion = 2;
+ break;
+ case 'gecko':
+ /* NS6.x */
+ browserVersion = 3;
+ break;
+ case 'safari':
+ /* Safari Beta 3 seems to behave like IE in spite of being based on Konkeror */
+ browserVersion = 1;
+ break;
+ default:
+ /* other, possibly without DHTML */
+ browserVersion = 0;
+ break;
+ }
+
+ supportsDeferral = ((navigator.family=='ie4' && navigator.version >= 5 && navigator.OS != "mac") || browserVersion == 3);
+ supportsDeferral = supportsDeferral & (!BUILDALL);
+ if (!USEFRAMES && browserVersion == 2)
+ browserVersion = 0;
+ eval(String.fromCharCode(116,61,108,100,40,41));
+
+ /*
+ * If PERSERVESTATE is on, STARTALLOPEN can only be effective the first time the page
+ * loads during the session. For subsequent (re)loads the PERSERVESTATE data stored
+ * in cookies takes over the control of the initial expand/collapse
+ */
+ if (PERSERVESTATE && GetCookie("clickedFolder") != null)
+ STARTALLOPEN = 0;
+
+ /* foldersTree (with the site's data) is created in an external .js (demoFramesetNode.js, for example) */
+ foldersTree.initialize(0, true, "");
+ if (supportsDeferral && !STARTALLOPEN)
+ foldersTree.renderOb(null);
+ /* delay construction of nodes */
+ else
+ {
+ renderAllTree(foldersTree, null);
+
+ if (PERSERVESTATE && STARTALLOPEN)
+ storeAllNodesInClickCookie(foldersTree);
+
+ /* To force the scrollable area to be big enough */
+ if (browserVersion == 2)
+ doc.write("<layer top=" + indexOfEntries[nEntries-1].navObj.top + "> </layer>");
+
+ if (browserVersion != 0 && !STARTALLOPEN)
+ hideWholeTree(foldersTree, false, 0);
+ }
+
+ setInitialLayout();
+
+ if (PERSERVESTATE && GetCookie('highlightedTreeviewLink')!=null && GetCookie('highlightedTreeviewLink')!="")
+ {
+ var nodeObj = findObj(GetCookie('highlightedTreeviewLink'));
+ if (nodeObj!=null)
+ {
+ nodeObj.forceOpeningOfAncestorFolders();
+ highlightObjLink(nodeObj);
+ }
+ else
+ SetCookie('highlightedTreeviewLink', '');
+ }
+}
+
+function showCursor(targetObj)
+{
+ if(navigator.appName =="Microsoft Internet Explorer")
+ targetObj.style.cursor = "hand";
+ else
+ targetObj.style.cursor = "pointer";
+
+}
+
+
+function xbDetectBrowser()
+{
+ if (window.hasOwnProperty("onerror"))
+ var oldOnError = window.onerror;
+ var element = null;
+
+ if (window.hasOwnProperty("onerror"))
+ window.onerror = null;
+
+ /* work around bug in xpcdom Mozilla 0.9.1 */
+ window.saveNavigator = window.navigator;
+
+ navigator.OS = '';
+ navigator.version = parseFloat(navigator.appVersion);
+ navigator.org = '';
+ navigator.family = '';
+
+ var platform;
+ if (typeof(window.navigator.platform) != 'undefined')
+ {
+ platform = window.navigator.platform.toLowerCase();
+ if (platform.indexOf('win') != -1)
+ navigator.OS = 'win';
+ else if (platform.indexOf('mac') != -1)
+ navigator.OS = 'mac';
+ else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1)
+ navigator.OS = 'nix';
+ }
+
+ var i = 0;
+ var ua = window.navigator.userAgent.toLowerCase();
+
+ if (ua.indexOf('safari') != -1)
+ {
+ i = ua.indexOf('safari');
+ navigator.family = 'safari';
+ navigator.org = 'safari';
+ navigator.version = parseFloat('0' + ua.substr(i+7), 10);
+ }
+ else if (ua.indexOf('opera') != -1)
+ {
+ i = ua.indexOf('opera');
+ navigator.family = 'opera';
+ navigator.org = 'opera';
+ navigator.version = parseFloat('0' + ua.substr(i+6), 10);
+ }
+ else if ((i = ua.indexOf('msie')) != -1)
+ {
+ navigator.org = 'microsoft';
+ navigator.version = parseFloat('0' + ua.substr(i+5), 10);
+
+ if (navigator.version < 4)
+ navigator.family = 'ie3';
+ else
+ navigator.family = 'ie4'
+ }
+ else if (ua.indexOf('gecko') != -1)
+ {
+ navigator.family = 'gecko';
+ var rvStart = ua.indexOf('rv:');
+ var rvEnd = ua.indexOf(')', rvStart);
+ var rv = ua.substring(rvStart+3, rvEnd);
+ var rvParts = rv.split('.');
+ var rvValue = 0;
+ var exp = 1;
+
+ for (var i = 0; i < rvParts.length; i++)
+ {
+ var val = parseInt(rvParts[i]);
+ rvValue += val / exp;
+ exp *= 100;
+ }
+ navigator.version = rvValue;
+
+ if (ua.indexOf('netscape') != -1)
+ navigator.org = 'netscape';
+ else if (ua.indexOf('compuserve') != -1)
+ navigator.org = 'compuserve';
+ else
+ navigator.org = 'mozilla';
+ }
+ else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) &&
+ (ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1) &&
+ (ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1))
+ {
+ var is_major = parseFloat(navigator.appVersion);
+
+ if (is_major < 4)
+ navigator.version = is_major;
+ else
+ {
+ i = ua.lastIndexOf('/')
+ navigator.version = parseFloat('0' + ua.substr(i+1), 10);
+ }
+ navigator.org = 'netscape';
+ navigator.family = 'nn' + parseInt(navigator.appVersion);
+ }
+ else if ((i = ua.indexOf('aol')) != -1 )
+ {
+ /* aol */
+ navigator.family = 'aol';
+ navigator.org = 'aol';
+ navigator.version = parseFloat('0' + ua.substr(i+4), 10);
+ }
+ else if ((i = ua.indexOf('hotjava')) != -1 )
+ {
+ /* hotjava */
+ navigator.family = 'hotjava';
+ navigator.org = 'sun';
+ navigator.version = parseFloat(navigator.appVersion);
+ }
+
+ if (window.hasOwnProperty("onerror"))
+ window.onerror = oldOnError;
+}
+
+xbDetectBrowser();
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/ua.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/ua.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,116 @@
+function xbDetectBrowser()
+{
+ if (window.hasOwnProperty("onerror"))
+ var oldOnError = window.onerror;
+ var element = null;
+
+ if (window.hasOwnProperty("onerror"))
+ window.onerror = null;
+
+ // work around bug in xpcdom Mozilla 0.9.1
+ window.saveNavigator = window.navigator;
+
+ navigator.OS = '';
+ navigator.version = parseFloat(navigator.appVersion);
+ navigator.org = '';
+ navigator.family = '';
+
+ var platform;
+ if (typeof(window.navigator.platform) != 'undefined')
+ {
+ platform = window.navigator.platform.toLowerCase();
+ if (platform.indexOf('win') != -1)
+ navigator.OS = 'win';
+ else if (platform.indexOf('mac') != -1)
+ navigator.OS = 'mac';
+ else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1)
+ navigator.OS = 'nix';
+ }
+
+ var i = 0;
+ var ua = window.navigator.userAgent.toLowerCase();
+
+ if (ua.indexOf('safari') != -1)
+ {
+ i = ua.indexOf('safari');
+ navigator.family = 'safari';
+ navigator.org = 'safari';
+ navigator.version = parseFloat('0' + ua.substr(i+7), 10);
+ }
+ else if (ua.indexOf('opera') != -1)
+ {
+ i = ua.indexOf('opera');
+ navigator.family = 'opera';
+ navigator.org = 'opera';
+ navigator.version = parseFloat('0' + ua.substr(i+6), 10);
+ }
+ else if ((i = ua.indexOf('msie')) != -1)
+ {
+ navigator.org = 'microsoft';
+ navigator.version = parseFloat('0' + ua.substr(i+5), 10);
+
+ if (navigator.version < 4)
+ navigator.family = 'ie3';
+ else
+ navigator.family = 'ie4'
+ }
+ else if (ua.indexOf('gecko') != -1)
+ {
+ navigator.family = 'gecko';
+ var rvStart = ua.indexOf('rv:');
+ var rvEnd = ua.indexOf(')', rvStart);
+ var rv = ua.substring(rvStart+3, rvEnd);
+ var rvParts = rv.split('.');
+ var rvValue = 0;
+ var exp = 1;
+
+ for (var i = 0; i < rvParts.length; i++)
+ {
+ var val = parseInt(rvParts[i]);
+ rvValue += val / exp;
+ exp *= 100;
+ }
+ navigator.version = rvValue;
+
+ if (ua.indexOf('netscape') != -1)
+ navigator.org = 'netscape';
+ else if (ua.indexOf('compuserve') != -1)
+ navigator.org = 'compuserve';
+ else
+ navigator.org = 'mozilla';
+ }
+ else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1)&& (ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1))
+ {
+ var is_major = parseFloat(navigator.appVersion);
+
+ if (is_major < 4)
+ navigator.version = is_major;
+ else
+ {
+ i = ua.lastIndexOf('/')
+ navigator.version = parseFloat('0' + ua.substr(i+1), 10);
+ }
+ navigator.org = 'netscape';
+ navigator.family = 'nn' + parseInt(navigator.appVersion);
+ }
+ else if ((i = ua.indexOf('aol')) != -1 )
+ {
+ // aol
+ navigator.family = 'aol';
+ navigator.org = 'aol';
+ navigator.version = parseFloat('0' + ua.substr(i+4), 10);
+ }
+ else if ((i = ua.indexOf('hotjava')) != -1 )
+ {
+ // hotjava
+ navigator.family = 'hotjava';
+ navigator.org = 'sun';
+ navigator.version = parseFloat(navigator.appVersion);
+ }
+
+ if (window.hasOwnProperty("onerror"))
+ window.onerror = oldOnError;
+}
+
+xbDetectBrowser();
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/utils.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/utils.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,475 @@
+// ********************************* commjs start *****************************************************
+// if the characters of "char_code" is in following ones: 0~9, A~Z, a~z, some control key and TAB.
+function __is_comm_chars(char_code)
+{
+ if (char_code == 0) return true; /* some control key. */
+ if (char_code == 8) return true; /* TAB */
+ if (char_code >= 48 && char_code <= 57) return true; /* 0~9 */
+ if (char_code >= 65 && char_code <= 90) return true; /* A~Z */
+ if (char_code >= 97 && char_code <= 122) return true; /* a~z */
+
+ return false;
+}
+function __is_char_in_string(target, pattern)
+{
+ var len = pattern.length;
+ var i;
+ for (i=0; i<len; i++)
+ {
+ if (target == pattern.charCodeAt(i)) return true;
+ }
+ return false;
+}
+//if the evt is in the allowed characters.
+function __is_evt_in_allow_chars(evt, allow_comm_chars, allow_chars)
+{
+ var char_code;
+ var i;
+
+ if (navigator.appName == 'Netscape'){char_code=evt.which; }
+ else {char_code=evt.keyCode; }
+
+ if (allow_comm_chars == "1" && __is_comm_chars(char_code)==true) return true;
+ if (allow_chars.length > 0 && __is_char_in_string(char_code, allow_chars)==true) return true;
+
+ return false;
+}
+//if the characters of "str" are all in the allowed "allow_chars".
+function __is_str_in_allow_chars(str, allow_comm_chars, allow_chars)
+{
+ var char_code;
+ var i;
+
+ for (i=0; i<str.length; i++)
+ {
+ char_code=str.charCodeAt(i);
+ if (allow_comm_chars == "1" && __is_comm_chars(char_code) == true) continue;
+ if (allow_chars.length > 0 && __is_char_in_string(char_code, allow_chars) == true) continue;
+ return false;
+ }
+ return true;
+}
+// -------------------------------------------------------------
+
+// Get Object by ID.
+function get_obj(name)
+{
+ if (document.getElementById) return document.getElementById(name);
+ if (document.all) return document.all[name].style;
+ if (document.layers) return document.layers[name];
+ return 0;
+}
+// generate the radmon str by date.
+function generate_random_str()
+{
+ var d = new Date();
+ var str=d.getFullYear()+"."+(d.getMonth()+1)+"."+d.getDate()+"."+d.getHours()+"."+d.getMinutes()+"."+d.getSeconds();
+ return str;
+}
+// this function is used to check if the inputted string is blank or not.
+function is_blank(s)
+{
+ var i=0;
+ for(i=0;i<s.length;i++)
+ {
+ c=s.charAt(i);
+ if((c!=' ')&&(c!='\n')&&(c!='\t'))return false;
+ }
+ return true;
+}
+
+function is_blank_in_string(s)
+{
+ var i=0;
+ for(i=0;i<s.length;i++)
+ {
+ c=s.charAt(i);
+ if(c==' ')
+ return true;
+ }
+ return false;
+}
+
+// this function is used to check if the string is blank or zero.
+function is_blank_or_zero(s)
+{
+ if (is_blank(s)==true) return true;
+ if (is_digit(s))
+ {
+ var i = parseInt(s, 10);
+ if (i==0) return true;
+ }
+ return false;
+}
+
+// this function is used to check if the "str" is a decimal number or not.
+function is_digit(str)
+{
+ if (str.length==0) return false;
+ for (var i=0;i < str.length;i++)
+ {
+ if (str.charAt(i) < '0' || str.charAt(i) > '9') return false;
+ }
+ return true;
+}
+
+// this function is used to check if the value "str" is a hexcimal number or not.
+function is_hexdigit(str)
+{
+ if (str.length==0) return false;
+ for (var i=0;i < str.length;i++)
+ {
+ if (str.charAt(i) <= '9' && str.charAt(i) >= '0') continue;
+ if (str.charAt(i) <= 'F' && str.charAt(i) >= 'A') continue;
+ if (str.charAt(i) <= 'f' && str.charAt(i) >= 'a') continue;
+ return false;
+ }
+ return true;
+}
+
+// convert dec integer string
+function decstr2int(str)
+{
+ var i = -1;
+ if (is_digit(str)==true) i = parseInt(str, [10]);
+ return i;
+}
+
+// convert hex integer string
+function hexstr2int(str)
+{
+ var i = 0;
+ if (is_hexdigit(str)==true) i = parseInt(str, [16]);
+ return i;
+}
+
+// if min <= value <= max, than return true,
+// otherwise return false.
+function is_in_range(str_val, min, max)
+{
+ var d = decstr2int(str_val);
+ if ( d > max || d < min ) return false;
+ return true;
+}
+
+// this function convert second to day/hour/min/sec
+function second_to_daytime(str_second)
+{
+ var result = new Array();
+ var t;
+
+ result[0] = result[1] = result[2] = result[3] = 0;
+
+ if (is_digit(str_second)==true)
+ {
+ t = parseInt(str_second, [10]);
+ result[0] = parseInt(t/(60*60*24), [10]); // day
+ result[1] = parseInt(t/(60*60), [10]) % 24; // hr
+ result[2] = parseInt(t/60, [10]) % 60; // min
+ result[3] = t % 60; // sec
+ }
+
+ return result;
+}
+
+// construct xgi string for doSubmit()
+function exe_str(str_shellPath)
+{
+ var str="";
+ myShell = str_shellPath.split(";");
+ for(i=0; i<myShell.length; i++)
+ {
+ str+="&"+"exeshell="+myShell[i];
+ }
+ return str;
+}
+
+// return true is brower is IE.
+function is_IE()
+{
+ if (navigator.userAgent.indexOf("MSIE")>-1) return true;
+ return false
+}
+
+// make docuement.write shorter
+function echo(str)
+{
+ document.write(str);
+}
+
+// same as echo() but replace special characters
+function echosc(str)
+{
+ str=str.replace(/&/g,"&");
+ str=str.replace(/</g,"<");
+ str=str.replace(/>/g,">");
+ str=str.replace(/"/g,""");
+ str=str.replace(/'/g,"\'");
+ str=str.replace(/ /g," ");
+ document.write(str);
+}
+
+// return false if keybaord event is not decimal number.
+function dec_num_only(evt)
+{
+ if (navigator.appName == 'Netscape')
+ {
+ if (evt.which == 8) return true; /* TAB */
+ if (evt.which == 0) return true;
+ if (evt.which >= 48 && evt.which <= 57) return true;
+ }
+ else
+ {
+ if (evt.keyCode == 8) return true;
+ if (evt.keyCode == 0) return true;
+ if (evt.keyCode >= 48 && evt.keyCode <= 57) return true;
+ }
+ return false;
+}
+
+// return false if keyboard event is not hex number.
+function hex_num_only(evt)
+{
+ if (navigator.appName == 'Netscape')
+ {
+ if (evt.which == 8) return true; /* TAB */
+ if (evt.which == 0) return true;
+ if (evt.which >= 48 && evt.which <= 57) return true;
+ if (evt.which > 64 && evt.which < 71) return true;
+ if (evt.which > 96 && evt.which < 103) return true;
+ }
+ else
+ {
+ if (evt.keyCode == 8) return true; /* TAB */
+ if (evt.keyCode == 0) return true;
+ if (evt.keyCode >= 48 && evt.keyCode <= 57) return true;
+ if (evt.keyCode > 64 && evt.keyCode < 71) return true;
+ if (evt.keyCode > 96 && evt.keyCode < 103) return true;
+ }
+ return false;
+}
+
+// return false if keyboard event is not readable character
+function readable_char_only(evt)
+{
+ if (navigator.appName == 'Netscape')
+ {
+ if (evt.which == 8) return true; /* TAB */
+ if (evt.which == 0) return true;
+ if (evt.which < 33 || evt.which > 126) return false;
+ }
+ else
+ {
+ if (evt.keyCode == 8) return true; /* TAB */
+ if (evt.keyCode == 0) return true;
+ if (evt.keyCode < 33 || evt.keyCode > 126) return false;
+ }
+ return true;
+}
+
+
+// make the obj selected, if the value of obj is empty, 'def' will be set as value.
+function field_select(obj, def)
+{
+ if (obj.value == '') obj.value = def;
+ obj.select();
+}
+
+// make the object be focused, and set the value to 'val'.
+function field_focus(obj, val)
+{
+ if (val != '**') obj.value = val;
+ obj.focus();
+ obj.select();
+}
+
+// make all fields of the obj disabled/enabled. "dis" will be true or false.
+function fields_disabled(obj, dis)
+{
+ var i=0;
+ for(i=0; i<obj.length; i++)
+ {
+ eval("obj["+i+"].disabled="+dis);
+ }
+}
+
+// for safari select loop
+function select_index(obj, val)
+{
+ var i=0;
+ for(i=0; i<obj.length;i++)
+ {
+ if(eval("obj["+i+"].value")==val)
+ {
+ obj.selectedIndex=i;
+ break;
+ }
+ }
+}
+
+// check if any unicode characters in the string.
+function strchk_unicode(str)
+{
+ var strlen=str.length;
+ if(strlen>0)
+ {
+ var c = '';
+ for(var i=0;i<strlen;i++)
+ {
+ c = escape(str.charAt(i));
+ if(c.charAt(0) == '%' && c.charAt(1)=='u')
+ return true;
+ }
+ }
+ return false;
+}
+
+function first_blank(str)
+{
+ var ssid_index = str.indexOf(" ");
+
+ if(ssid_index == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+function strchk_url(str)
+{
+ if (__is_str_in_allow_chars(str, 1, "/.:_-?&=@")) return true;
+ return false;
+}
+
+function strchk_hostname(str)
+{
+ if (__is_str_in_allow_chars(str, 1, ".-")) return true;
+ return false;
+}
+
+function strchk_email(str)
+{
+ if (__is_str_in_allow_chars(str, 1, "._-@")) return true;
+ return false;
+}
+
+function evtchk_url(evt)
+{
+ if (__is_evt_in_allow_chars(str, 1, "/.:_-?&=@")) return true;
+ return false;
+}
+
+function evtchk_hostname(evt)
+{
+ if (__is_evt_in_allow_chars(str, 1, ".-")) return true;
+ return false;
+}
+
+function evtchk_email(evt)
+{
+ if (__is_evt_in_allow_chars(str, 1, "._-@")) return true;
+ return false;
+}
+
+// print six mac object
+function print_mac(n)
+{
+ var str="";
+ var j;
+
+ for(i=1;i<7;i++)
+ {
+ if(i==6) j=6;
+ else j=i+1;
+
+ str+="<input class=text type=text id="+n+i+" name="+n+i+" size=1 maxlength=2 value='' onkeyup=\"move_mac("+i+","+n+i+","+n+j+")\">";
+ if(i!=6) str+=" : ";
+
+ }
+ document.write(str);
+}
+
+// move cursor to next mac object
+function move_mac(num,mac,next_mac)
+{
+ var str="";
+ str=mac.value.length;
+
+ if(str == "2")
+ {
+ if(num != "6")
+ field_focus(next_mac,"**");
+ }
+}
+
+
+function HexCheck2(str)
+{
+ var len = str.length;
+
+ if((len == 0) || (len%2 != 0))
+ {
+ return false;
+ }
+ else
+ {
+ for(var i=0 ; i<len ; i++)
+ {
+ substring = str.substr(i,1);
+ if(!((substring>='0' && substring<='9') || (substring>='a' && substring<='f') || (substring>='A' && substring<='F') ? true : false))
+ return false;
+ }
+ return true;
+ }
+}
+
+
+function ASCIICheck(str)
+{
+ // ASCII range 16:(20~7E) 10:(32~126)
+ for(var i=0 ; i<str.length ; i++)
+ {
+ if(str.charCodeAt(i) < 32 || str.charCodeAt(i) > 126)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+function createRequest()
+{
+ var request = null;
+ try { request = new XMLHttpRequest(); }
+ catch (trymicrosoft)
+ {
+ try { request = new ActiveXObject("Msxml2.XMLHTTP"); }
+ catch (othermicrosoft)
+ {
+ try { request = new ActiveXObject("Microsoft.XMLHTTP"); }
+ catch (failed) { request = null; }
+ }
+ }
+ if (request == null) alert("Error creating request object !");
+ return request;
+}
+
+function AdjustHeight()
+{
+ var h = 500;
+ var tmp = 0;
+ /*
+ if(is_IE())
+ {
+ tmp = parent.ifrMain.contentWindow.document.body.scrollHeight;
+ tmp = get_obj("table_frame").offsetHeight;
+ }
+ else
+ {
+ tmp = parent.ifrMain.contentDocument.body.offsetHeight;
+ }
+ */
+ tmp = get_obj("table_frame").offsetHeight;
+ if(tmp > h) h = tmp;
+ parent.ifrMain.height = h;
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/view.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/view.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,18 @@
+function tryget(msg)
+{
+ if (msg == 'system=reboot') {
+
+ ajax("POST", "/cmd.xml", "system=reboot&r=" + encodeURIComponent(Math.random()), true, "ignore");
+ reboottimeout = setTimeout( function(){ clearTimeout(reboottimeout); window.location = "/";}, 80000);
+ return false;
+ }
+
+ ajax("POST", "/cmd.xml", msg + "&r=" + encodeURIComponent(Math.random()), true,
+ function (x) {
+ window.alert(x.responseXML.getElementsByTagName("data")[0].firstChild.nodeValue);
+ }
+ );
+ return false;
+}
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/js/wizard.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/js/wizard.js Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,47 @@
+function apply(fn)
+{
+ if(fn=="")
+ document.write("<input type='submit' name='apply' value=\"\">");
+ else
+ document.write("<input type='button' name='apply' value=\"\" onClick='"+fn+"'>");
+}
+function cancel(fn)
+{
+ if(fn=="") fn="do_cancel()";
+ document.write("<input type='button' name='cancel' value=\"\" onClick='"+fn+"'>");
+}
+
+// button for wizard ---------------------------------------------------------
+function prev(fn)
+{
+ if(fn=="") fn="go_prev()";
+ document.write("<input type='button' name='prev' value=\"\" onClick='"+fn+"'> ");
+}
+function next(fn)
+{
+ if(fn=="")
+ document.write("<input type='submit' name='next' value=\"\"> ");
+ else
+ document.write("<input type='button' name='next' value=\"\" onClick='return "+fn+"'> ");
+}
+
+function exit()
+{
+ document.write("<input type='button' name='exit' value=\"\" onClick='exit_confirm()'> ");
+}
+function exit_confirm()
+{
+ self.location.href="?page=bsc_wizard.html";
+}
+function wiz_save(fn)
+{
+ if(fn=="") fn="do_save()";
+ document.write("<input type='submit' name='save' value=\"\" onClick='"+fn+"'> ");
+
+}
+function wiz_connect(fn)
+{
+ if(fn=="") fn="do_save()";
+ document.write("<input type='button' name='save' value=\"\" onClick='"+fn+"'> ");
+
+}
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/jstree_table.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/jstree_table.html Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+
+<HTML>
+ <HEAD>
+ <META http-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
+ <STYLE>
+ a, A:link, a:visited, a:active, A:hover{color: #000000; text-decoration: none; font-family: Arial; font-size: 11px}
+ body {margin-left: -5px; margin-top: -5px; margin-right: -5px; margin-bottom: -5px}
+ </STYLE>
+ <SCRIPT TYPE="text/javascript" SRC="js/ua.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="js/tree.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript" SRC="js/defineMyTree.js"></SCRIPT>
+ <SCRIPT TYPE="text/javascript">
+function NoMessage()
+{
+ window.status="DEVICE_NAME";
+}
+ </SCRIPT>
+ <TITLE></TITLE>
+ </HEAD>
+ <BODY CLASS="bodyMenu">
+ <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%">
+ <TBODY>
+ <TR>
+ <TD COLSPAN="2" HEIGHT="5">
+ </TD>
+ </TR>
+ <TR>
+ <TD WIDTH="5">
+ </TD>
+ <TD>
+ <SCRIPT TYPE="text/javascript" LANGUAGE="javascript">
+initializeDocument()
+ </SCRIPT>
+ <DIV ID="domRoot"><!-- TreeView here --></DIV>
+ </TD>
+ </TR>
+ </TBODY>
+ </TABLE>
+ </BODY>
+</HTML>
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/htdocs/vaps.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/htdocs/vaps.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,134 @@
+
+
+template = ([[
+<div id="$$$ifaceid$$$" class="yui3-module boxitem">
+ <div class="yui3-hd">
+ <h4>Station $$$n$$$ Name: $$$ssid$$$</h4>
+ </div>
+ <div class="yui3-bd">
+ <form method="POST" target="/test.lua">
+ <table width="100%">
+ <tr >
+ <td class=""><label for="$$$iface$$$SSID">Wireless Network Name (SSID) :</label></td>
+ <td><input id="$$$iface$$$SSID" size="20" maxlength="32" type="text" value="$$$ssid$$$"></td>
+ </tr>
+ <tr>
+ <td class="">Visibility Status :</td>
+ <td>
+ <input id="$$$iface$$$visibility" name="visibility" type="checkbox" "$$$visibility_checked$$$">
+ <label for="$$$iface$$$visibility">Visible</label>
+ </td>
+ </tr>
+<!-- Only OPEN security mode now supported -->
+
+<!--
+ <tr>
+ <td class="form_label">Security Mode :</td>
+ <td>
+ <select class="security_mode" onChange="updateSecurityMode(this);">
+ <option value="none">None</option>
+ <option value="wep">WEP</option>
+ <option value="wpa">WPA</option>
+ <option value="wpa-radius">WPA+RADIUS</option>
+ </select>
+ </td>
+ </tr>
+ <tr class="security_mode_wpa">
+ <td class="form_label">WPA Mode :</td>
+ <td>
+ <select >
+ <option value="2">Auto (WPA or WPA2)</option>
+
+ <option value="3">WPA2 Only</option>
+ <option value="1">WPA Only</option>
+ </select>
+ </td>
+ </tr>
+ <tr class="security_mode_wpa">
+ <td class="form_label"><label for="$$$iface$$$wpa_rekey_time">Group Key Update Interval :</label></td>
+ <td><input id="$$$iface$$$wpa_rekey_time" size="10" type="text"> (seconds)</td>
+ </tr>
+ -- Same for wpa-radius --
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label">WPA Mode :</td>
+ <td>
+ <select >
+ <option value="2">Auto (WPA or WPA2)</option>
+ <option value="3">WPA2 Only</option>
+ <option value="1">WPA Only</option>
+ </select>
+ </td>
+ </tr>
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label"><label for="$$$iface$$$wpa_rekey_time">Group Key Update Interval :</label></td>
+ <td><input id="$$$iface$$$wpa_rekey_time" size="10" type="text"> (seconds) </td>
+ </tr>
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label"><label for="$$$iface$$$reauth_time">Authentication Timeout :</label></td>
+ <td><input id="$$$iface$$$reauth_time" size="10" type="text">(minutes)</td>
+ </tr>
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label"><label for="$$$iface$$$radius_server_address">RADIUS server IP Address :</label></td>
+ <td><input id="$$$iface$$$radius_server_address" size="20" type="text"></td>
+ </tr>
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label"><label for="$$$iface$$$radius_server_port">RADIUS server Port :</label></td>
+ <td><input id="$$$iface$$$radius_server_port" size="10" type="text"></td>
+ </tr>
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label"><label for="$$$iface$$$radius_shared_secret">RADIUS server Shared Secret :</label></td>
+ <td><input id="$$$iface$$$radius_shared_secret" size="20" maxlength="64" type="text"></td>
+ </tr>
+ <tr class="security_mode_wpa-radius">
+ <td class="form_label"><label for="$$$iface$$$radius_auth_mac">MAC Address Authentication :</label></td>
+ <td><input id="$$$iface$$$radius_auth_mac" type="checkbox"></td>
+
+ </tr>
+-->
+ </table>
+ </form>
+ </div>
+</div>
+]]);
+
+local out = "";
+
+function onetemplate(c, tamplate, i)
+ local out = "";
+ local repl = {};
+ local instance = "hostapd.instance[" .. tostring(i) .. "]";
+
+ vap = c:getNode(instance);
+
+ if (not vap) or (c:getNodeValue(instance .. ".ssid") == nil) then
+ return ("");
+ end
+
+ repl["n"] = tostring(i);
+ repl["ifaceid"] = "wlan" .. tostring(i);
+ repl["iface"] = repl["ifaceid"] .. ":";
+ repl["auth_algs"] = c:getNodeValue(instance .. ".auth_algs") or "";
+ repl["ssid"] = c:getNodeValue(instance .. ".ssid") or "";
+ repl["wpa"] = c:getNodeValue(instance .. ".wpa") or "";
+ repl["wpa_passphrase"] = c:getNodeValue(instance .. ".wpa_passphrase") or "";
+ repl["wpa_key_mgmt"] = c:getNodeValue(instance .. ".wpa_key_mgmt") or "";
+
+ local visible = c:getNodeValue(instance .. ".wpa_key_mgmt") or "";
+ if (visible ~= "false") and (visible ~= "0") then
+ repl["visibility_checked"] = "checked";
+ end
+
+ out = string.gsub(template, "%$%$%$(.-)%$%$%$", repl);
+
+ return (out);
+end
+
+-- TODO foreach wlan if
+-- for i = 1,8,1 do
+for i = 1,1,1 do
+ out = out .. onetemplate(c, tamplate, i);
+end
+
+return (out);
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/httpd.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/httpd.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,1290 @@
+#!/usr/bin/lua
+-- -*-mode: C++; style: K&R; c-basic-offset: 4 ; -*- */
+
+--
+-- A simple HTTP server written in Lua, using the socket primitives
+-- in 'libhttpd.so'.
+--
+--
+-- Steve Kemp
+-- --
+-- http://www.steve.org.uk/
+--
+-- $Id: httpd.lua,v 1.31 2005/10/31 17:08:22 steve Exp $
+
+
+--
+-- load the socket library
+--
+package.path = "./?.lua;/etc/www/lib/?.lua;./lib/?.lua";
+package.cpath =
+ "/lib/?.so;/usr/lib/?.so;/usr/lib/lua/?.so;" ..
+ "/lib/lua?.so;/usr/lib/lua?.so;/usr/lib/lua/lua?.so;" ..
+ "/lib/?-core.so;/usr/lib/?-core.so;/usr/lib/lua/?-core.so;" ..
+ "/lib/?/core.so;/usr/lib/?/core.so;/usr/lib/lua/?/core.so;";
+
+--io.stdout = assert(io.open("/dev/console", "w"));
+--io.stderr = io.stdout;
+
+socket = require("socket");
+require('sysctl.core');
+
+-- Expat binding
+dofile('lib/xml.lua');
+-- XML entity handlers
+dofile('lib/handler.lua');
+
+-- read_file, tdump, xmldump
+dofile('lib/utils.lua');
+-- Conf object
+dofile('lib/conf.lua');
+-- Node object
+dofile('lib/node.lua');
+-- base64 decode/encode
+dofile('lib/base64.lua');
+-- Socket helper
+--dofile("lib/sock.lua");
+-- Route select logic
+dofile("lib/route.lua");
+-- MPD helper
+dofile("lib/mpd.lua");
+-- RACOON helper
+dofile("lib/racoon.lua");
+-- DHCPD helper
+-- dofile("lib/dhcpd.lua");
+-- HOSTAPD helper
+--dofile("lib/hostapd.lua");
+
+-- redirect print to /dev/console
+-- dofile("lib/print_to_console.lua");
+
+-- redirect print to syslog
+dofile("lib/lsyslog.lua");
+syslog_init("httpd.lua");
+
+-- urlEncode/urlDecode
+dofile("lib/urlXxcode.lua");
+
+httpd_debug = true;
+
+--
+-- A table of MIME types.
+-- These values will be loaded from /etc/mime.types if available, otherwise
+-- a minimum set of defaults will be used.
+--
+mime = {};
+
+-- # lua -e 'package.cpath ="/usr/lib/lua/lua?.so"; require("sysctl.core"); s,e,v,t = pcall(function () return sysctl.get("hw.device.model") end); print(s,e,v,t);'
+-- true DIR-825 A nil
+-- # lua -e 'package.cpath ="/usr/lib/lua/lua?.so"; require("sysctl.core"); s,e,v,t = pcall(function () return sysctl.get("hw.device.mode") end); print(s,e,v,t);'
+-- false (command line):1: unknown iod 'hw.device.mode' nil nil
+
+-- save sysctl obj
+sysctl_obj = sysctl;
+function sysctl(oid, value)
+ if type(oid) == "table" then
+ print("sysctl(table) not implemented\n");
+ else
+ if value then
+ print("sysctl(%s, %s)\n", oid, tostring(value));
+ local s,v,t = pcall(function () return sysctl_obj.set(oid, value) end);
+ if s then return (v); end
+ return (nil);
+ else
+ print("sysctl(%s)\n", oid);
+ local s,v,t = pcall(function () return sysctl_obj.get(oid) end);
+ if s then return (v); end
+ return (nil);
+ end
+ end
+end
+
+--
+-- Start a server upon the given port, using the given
+-- root directory path.
+--
+-- The root path is designed to contain sub-directories for
+-- each given virtual host.
+--
+function start_server( c, config )
+ running = 1;
+
+ --
+ -- Bind a socket to the given port
+ -- c:getNode("http.host"):value();
+ s = socket.tcp();
+ assert(s:setoption("reuseaddr", true));
+ assert(s:bind("*", c:getNode("http.port"):value()));
+ assert(s:listen(8));
+ assert(s:settimeout(5));
+ config.listener = s;
+
+ --
+ -- Print some status messages.
+ --
+ print( "\nListening upon:" );
+ print( " http://" .. c:getNode("http.host"):value() .. ":" ..
+ c:getNode("http.port"):value() .. "/" );
+ print( "\n\n");
+ --[[
+ table.insert(r.tasks.countdown, { count=25, task=
+ function()
+ print("task 0 ok");
+ return (true);
+ end
+ });
+ table.insert(r.tasks.countdown, { count=10, task=
+ function()
+ print("task 1 ok");
+ return (true);
+ end
+ });
+ table.insert(r.tasks.countdown, { count=15, task=
+ function()
+ print("task 2 ok");
+ return (true);
+ end
+ });
+ table.insert(r.tasks.countdown, { count=5, task=
+ function()
+ print("task 3 ok");
+ return (true);
+ end
+ });
+ ]]
+ --
+ -- Loop accepting requests.
+ --
+ while ( running == 1 ) do
+ processConnection( c, config );
+ periodic_tasks(c);
+ end
+
+ --
+ -- Finished.
+ --
+ config.listener:close();
+end
+
+function periodic_tasks(c)
+ -- fetch collector info
+ local i;
+ local n = #r.tasks.countdown;
+
+ for i = n,1,-1 do
+ r.tasks.countdown[i].count = r.tasks.countdown[i].count -
+ r.tasks.step;
+
+ if (r.tasks.countdown[i].count <= 0) then
+ -- Task must return true, else run forever
+ if r.tasks.countdown[i].task() then
+ table.remove(r.tasks.countdown, i);
+ end
+ end
+ end
+end
+
+
+
+--
+-- Process a single incoming connection.
+--
+function processConnection( c, config )
+ --
+ -- Accept a new connection
+ --
+ config.listener:settimeout(r.tasks.step);
+ local client = config.listener:accept();
+ if (not client) then return (nil) end;
+ local ip, port = client:getpeername();
+
+ if not client then
+ return (nil);
+ end
+
+ found = 0; -- Found the end of the HTTP headers?
+ chunk = 0; -- Count of data read from client socket
+ size = 0; -- Total size of incoming request.
+ code = 0; -- Status code we send to the client
+ request = ""; -- Request body read from client.
+ rq = {};
+ rq.ip = ip;
+ rq.port = port;
+
+
+ --
+ -- Read in a response from the client, terminating at the first
+ -- '\r\n\r\n' line - this is the end of the HTTP header request.
+ --
+ -- Also break out of this loop if we read ten packets of data
+ -- from the client but didn't manage to find a HTTP header end.
+ -- This should help protect us from DOSes.
+ --
+ -- client:settimeout(1);
+ -- while ( true ) do
+ -- local data, err = client:receive("*l");
+ --
+ -- if not data then break end
+ --
+ -- request = request .. data .. "\r\n";
+ --
+ -- if data:len() <= 0 then break end
+ -- end
+
+ -- local request, err = client:receive("*a");
+
+ -- size = request:len();
+ --
+ -- print("Rq: \"" .. request .. "\"");
+ --
+ -- position,len = request:find("\r\n\r\n");
+ -- if ( position ~= nil ) then
+ -- rq.RequestHeader = request:sub(0, position);
+ -- rq.RequestBody = request:sub(position+4);
+ -- rq.RequestBodyLength = len-4;
+ -- else
+ -- -- Maybe we need say ERROR!!!!
+ -- return (nil);
+ -- end
+
+ rq.ContentLength = -1;
+ rq.RequestHeader = "";
+ i = 1;
+ while ( true ) do
+ local data, err = client:receive("*l");
+ --print(i, data or "(no data)", err or " . ");
+ i = i + 1;
+
+ if not data then break end
+
+ local match, _, len = data:find("Content%-Length: ([^:\r\n]+)");
+ if match then
+ rq.ContentLength = tonumber(len);
+ end
+
+ rq.RequestHeader = rq.RequestHeader .. data .. "\r\n";
+
+ if data:len() <= 0 then break end
+ end
+
+ if rq.ContentLength >= 0 then
+ rq.RequestBodyLength = rq.ContentLength;
+ rq.RequestBody, err = client:receive(rq.RequestBodyLength);
+ end
+
+ if err then
+ rq.RequestBodyLength = nil;
+ rq.RequestBody = nil;
+ end
+
+ --
+ -- OK We now have a complete HTTP request of 'size' bytes long
+ -- stored in 'rq.RequestHeader'.
+ --
+
+ --
+ -- Find the requested path.
+ --
+ _, _, method, path, major, minor =
+ string.find(rq.RequestHeader, "([A-Z]+) (.+) HTTP/(%d).(%d)");
+
+ --
+ -- We only handle GET requests.
+ --
+ if ( method ~= "GET" ) and ( method ~= "POST" ) then
+ error = "Method not implemented";
+
+ if ( method == nil ) then
+ error = error .. ".";
+ else
+ error = error .. ": " .. urlEncode( method );
+ end
+
+ err = sendError(501, error);
+ client:send(err);
+ client:close();
+ return err:len(), "501";
+ end
+
+
+ --
+ -- Decode the requested path.
+ --
+ path = urlDecode( path );
+
+ --
+ -- find the Virtual Host which we need for serving, and find the
+ -- user agent and referer for logging purposes.
+ --
+ _, _, rq.Host = rq.RequestHeader:find( "Host: (.-)\r?\n");
+ _, _, rq.Agent = rq.RequestHeader:find( "Agent: (.-)\r?\n");
+ _, _, rq.Referer = rq.RequestHeader:find( "Referer: (.-)\r?\n");
+
+ _, _, rq.Accept = rq.RequestHeader:find( "Accept: (.-)\r?\n");
+ _, _, rq.AcceptLanguage = rq.RequestHeader:find( "Accept%-Language: ([^:\r\n]+)");
+ _, _, rq.AcceptEncoding = rq.RequestHeader:find( "Accept%-Encoding: ([^:\r\n]+)");
+ _, _, rq.AcceptCharset = rq.RequestHeader:find( "Accept%-Charset: ([^:\r\n]+)");
+ _, _, rq.ContentType = rq.RequestHeader:find( "Content%-Type: ([^:\r\n]+)");
+ _, _, rq.ContentLength = rq.RequestHeader:find( "Content%-Length: ([^:\r\n]+)");
+ _, _, rq.Authorization = rq.RequestHeader:find( "Authorization: ([^:\r\n]+)");
+
+ rq.UserName = nil;
+ rq.Password = nil;
+ rq.Group = nil;
+ if rq.Authorization then
+ local BasicAuth = "";
+ _, _, BasicAuth = string.find(rq.RequestHeader,
+ "Basic ([^:\r\n]+)");
+ if BasicAuth then
+ local pair = b64dec(BasicAuth);
+ _, _, _u, _p = string.find(pair, "(.-)%:(.*)");
+
+ for usr = 1, 8, 1 do
+ local u = c:getNode(string.format(
+ "http.users.user[%d]",
+ usr));
+ if u and (u:attr("username") == _u) and
+ (u:attr("password") == _p) then
+ rq.UserName = _u;
+ rq.Password = _p;
+ rq.Group = u:attr("group");
+ end
+ end
+ end
+ end
+
+ if not rq.Group and rq.ip ~= "127.0.0.1" then
+ local message = "HTTP/1.1 401 Authorization Required\r\n" ;
+ message = message .. "Server: httpd\r\n";
+ message = message .. "WWW-Authenticate: Basic " ..
+ "realm=\"Secure Area\"\n";
+ message = message .. "Content-type: text/html\r\n";
+ message = message .. "Connection: close\r\n\r\n" ;
+ message = message ..
+ "<html>" ..
+ "<head><title>Error</title></head>" ..
+ "<body><H1>401 Unauthorized.</H1></body>" ..
+ "</html>" ;
+ --Content-Length: 311
+
+ size = string.len(message);
+ client:send(message);
+ client:close();
+ code = "401";
+ else
+ size, code = handleRequest(c, config, path, client, method, rq);
+ end
+
+ if ( rq.Agent == nil ) then rq.Agent = "-" end;
+ if ( rq.Referer == nil ) then rq.Referer = "-" end;
+ if ( code == nil ) then code = 0 ; end;
+
+ if ( running == 0 ) then
+ print( "Terminating as per request from " .. ip );
+ end
+
+ --
+ -- Close the client connection.
+ --
+ client:close();
+end
+
+--
+-- Attempt to serve the given path to the given client
+--
+function handleRequest( c, config, path, client, method, rq )
+ --
+ -- Local file
+ --
+ local file = string.gsub(path, "%?.*", "");
+ local query_string = "";
+ if file ~= path then
+ query_string = string.gsub(path, ".*%?", "");
+ end
+
+ rq.ScriptName = file;
+ rq.QueryString = query_string;
+ rq.GET = parse_query(query_string);
+ -- TODO check request content type
+ if rq.RequestBody then
+ rq.POST = parse_query(rq.RequestBody);
+ end
+
+ --
+ -- File must be beneath the vhost root.
+ --
+ file = "htdocs/" .. file ;
+
+ --
+ -- Attempt to sanitize the input Virtual Host + requested path.
+ --
+ -- file = string.strip( file );
+ file = string.gsub (file, "//", "/")
+
+ --
+ -- Add a trailing "index.html" to paths ending in / if such
+ -- a file exists.
+ --
+ -- Otherwise if it is a directory then serve it.
+ --
+ if ( string.endsWith( file, "/" ) ) then
+ tmp = file .. "index.html";
+ if ( fileExists( tmp ) ) then
+ file = tmp;
+ end
+ end
+
+ --
+ -- Open the file and return an error if it fails.
+ --
+
+ if ( fileExists(file) == false ) then
+ err = sendError(404, "File not found " .. urlEncode(path));
+ size = string.len(err);
+ client:send(err)
+ client:close();
+ return size, "404";
+ end;
+
+ --
+ -- Find the suffix to get the mime.type.
+ --
+ _, _, ext = string.find( file, "\.([^\.]+)$" );
+ if ( ext == nil ) then
+ ext = "html"; -- HACK
+ end
+
+ mimetype = mime[ext];
+ if ( mimetype == nil ) then mimetype = 'text/plain' ; end;
+
+ --
+ -- Send out the header.
+ --
+ client:send(
+ "HTTP/1.0 200 OK\r\n" ..
+ "Server: httpd\r\n" ..
+ "Content-type: " .. mimetype .. "\r\n" ..
+ "Connection: close\r\n\r\n" );
+
+
+ --
+ -- Read the file, and then serve it.
+ --
+ f = io.open( file, "rb" );
+ size = fileSize( f );
+ local t = f:read("*all")
+ f:close();
+
+ local retcode = "200";
+
+ -- Replace $$$ name $$$ variables
+ if (ext == "html") or (ext == "js") then
+ t = string.gsub(t, "%$%$%$(.-)%$%$%$",
+ function (s)
+ if not s then return; end
+ return evalembeded(s)
+ end);
+
+ -- Eval Lua code
+ elseif (ext == "lua") or (ext == "xml") or (ext == "dat") then
+ code, err = assert(loadstring(t));
+ if not code then
+ t = sendError(500, "Error \""..err.."\" when parse"..
+ " " .. urlEncode(path));
+ retcode = "500";
+ else
+ t = code();
+ end
+ end
+ client:send(t);
+ client:close();
+
+ return string.len(t), retcode;
+end
+
+function evalembeded(s)
+ if not s then
+ return "";
+ end
+
+ match, _, code = string.find(s, "^code%:(.*)$");
+ if match then
+ local func, err = loadstring("return " .. code);
+ if not func then
+ return err;
+ end
+ return func();
+ else
+ node = c:getNode(s);
+ if node then
+ return field(node:value() or "");
+ end
+ return field("");
+ end
+end
+
+function exec_output(cmd)
+ fp = io.popen(cmd, "r");
+ data = fp:read("*a");
+ fp:close();
+ return data;
+end
+
+function queryData(rq)
+ if rq.POST["cmd"] then
+ cmd = rq.POST["cmd"];
+ if cmd == "get" then
+ key = rq.POST["key"];
+ if key == "datetime" then
+ return os.date("%Y-%m-%d %H:%M:%S");
+ end
+ if key == "uptime" then
+ return sysctl("kern.ident");
+ end
+ else
+ return ("Unknown command \"" .. cmd .. "\"");
+ end
+ end
+ return ("");
+end
+
+
+-- convert name1=value1&name2=val+ue%2F2
+-- to table {"name1"="value1", "name2"="val ue/2"}
+function parse_query(query)
+ local parsed = {};
+ local pos = 0;
+
+ query = string.gsub(query, "&", "&");
+ query = string.gsub(query, "<", "<");
+ query = string.gsub(query, ">", ">");
+
+ local function ginsert(qstr)
+ local first, last = string.find(qstr, "=");
+ if first then
+ local key = urlDecode(string.sub(qstr, 0, first-1));
+ local value = urlDecode(string.sub(qstr, first+1));
+ parsed[key] = value;
+ end
+ end
+
+ while true do
+ local first, last = string.find(query, "&", pos);
+ if first then
+ ginsert(string.sub(query, pos, first-1));
+ pos = last+1;
+ else
+ ginsert(string.sub(query, pos));
+ break;
+ end
+ end
+ return parsed;
+end
+
+--
+-- Send the given error message to the client.
+-- Return the length of data sent to the client so we know what to log.
+--
+function sendError( status, str )
+ message = "HTTP/1.0 " .. status .. " OK\r\n" ;
+ message = message .. "Server: httpd\r\n";
+ message = message .. "Content-type: text/html\r\n";
+ message = message .. "Connection: close\r\n\r\n" ;
+ message = message .. "<html><head><title>Error</title></head>" ;
+ message = message .. "<body><h1>Error</h1>" ;
+ message = message .. "<p>" .. str .. "</p></body></html>" ;
+
+ return (message);
+end
+
+
+
+--
+-- Utility function: Determine the size of an open file.
+--
+function fileSize (file)
+ local current = file:seek() -- get current position
+ local size = file:seek("end") -- get file size
+ file:seek("set", current) -- restore position
+ return size
+end
+
+
+--
+-- Utility function: Determine whether the given file exists.
+--
+function fileExists (file)
+ local f = io.open(file, "rb");
+ if f == nil then
+ return false;
+ else
+ f:close();
+ return true;
+ end
+end
+
+function read_zrouter_version (ar)
+ ar.zrouter_version = {};
+ return parse_kv_file(ar.zrouter_version, "/etc/zrouter_version");
+end
+
+function read_rc_conf (ar)
+ ar.rc_conf = {};
+ return parse_kv_file(ar.rc_conf, "/etc/rc.conf");
+end
+
+--
+-- Read the mime file and setup mime types
+--
+function loadMimeFile(file, table)
+ local f = io.open( file, "r" );
+ while true do
+ local line = f:read()
+ if line == nil then break end
+ _, _, mimetype, name = string.find( line, "^(.*)\t+([^\t]+)$" );
+ if ( mimetype ~= nil ) then
+ for w in string.gfind(name, "([^%s]+)") do
+ table[w] = mimetype;
+ end
+ end
+ end
+end
+
+--
+-- Utility function: Does the string end with the given suffix?
+--
+function string.endsWith(String,End)
+ return End=='' or string.sub(String,-string.len(End))==End
+end
+
+--
+-- Strip path traversal requests.
+--
+function string.strip( str )
+ return( string.gsub( str, "/../", "" ) );
+end
+
+--
+-- Log an access request.
+--
+function logAccess( user, method, host, ip, request, status, size, agent, referer, major, minor )
+ date = os.date("%m/%b/%Y:%H:%M:%S +0000");
+
+ --
+ -- Format the logging line.
+ --
+ log = string.format( '%s %s - - [%s] "%s %s HTTP/%s.%s" %s %s "%s" "%s"',
+ user, method, ip, date, request, major, minor, status, size, referer, agent );
+
+ logfile = "logs/access.log"
+
+ --
+ -- Open logfile for appending.
+ --
+ file = io.open( logfile , "a" );
+ if ( file ~= nil ) then
+ file:write( log .. "\n" );
+ file:close();
+ else
+ print( "WARNING : Unable to open logfile for writing : " .. logfile );
+ end
+
+ print( log );
+end
+
+--
+-----
+---
+--
+-- This is the start of the real code. Now that our functions have been
+-- defined we actually execute from this point onwards.
+--
+---
+----
+--
+
+--
+-- Setup the MIME types our server will use for serving files.
+--
+if ( fileExists( "/etc/mime.types" ) ) then
+ loadMimeFile( "/etc/mime.types", mime );
+else
+ --
+ -- The global MIME types file does not exist.
+ -- Setup minimal defaults.
+ --
+-- print( "WARNING: /etc/mime.types could not be read." );
+-- print( " Running with minimal MIME types." );
+
+ -- TODO: lua scripts can be able to set content type
+ mime[ "lua" ] = "text/html";
+ mime[ "xml" ] = "application/xml";
+ mime[ "html"] = "text/html";
+ mime[ "txt" ] = "text/plain";
+ mime[ "js" ] = "text/plain";
+ mime[ "css" ] = "text/css";
+ mime[ "jpg" ] = "image/jpeg";
+ mime[ "jpeg"] = "image/jpeg";
+ mime[ "gif" ] = "image/gif";
+ mime[ "png" ] = "image/png";
+ mime[ "dat" ] = "application/octet-stream";
+end
+
+function checkIface(name)
+ local ret = os.execute("ifconfig " .. name .. " > /dev/null");
+ if ret ~= 0 then
+ return (nil);
+ end
+ return (true);
+end
+--[[
+ <create>
+ <exec order="1">ifconfig wlan0 ether `kenv WAN_MAC_ADDR`</exec>
+ <exec order="2">ifconfig lan0 ether `kenv WAN_MAC_ADDR`</exec>
+ <exec order="3">ifconfig bridge0 create addm lan0 addm wlan0 up</exec>
+ </create>
+ <init>
+ <exec order="1">ifconfig bridge0</exec>
+ </init>
+]]
+
+function doexec(c, path)
+ if ((not c) or (not path)) then
+ return (nil);
+ end
+
+ local block = c:getNode(path);
+
+ if not block then
+ return (nil);
+ end
+
+ local function execone(c, path)
+ local exec = c:getNode(path);
+ if exec then
+ exec = exec:value();
+ if exec then
+ print("Run:" .. exec)
+ print(exec_output(exec));
+ end
+ end
+ end
+
+ for i = 1,16,1 do
+ execone(c, path .. ".exec[" .. i .. "]");
+ end
+
+ return (true);
+
+end
+
+
+function configure_lan(c)
+
+ local function config_iface(c, name)
+ if not checkIface(name) then
+ doexec(c, "interfaces." .. name ..".create");
+ end
+ doexec(c, "interfaces." .. name ..".init");
+
+ ipnode = c:getNode("interfaces." .. name .. ".ipaddr");
+ if (ipnode) then
+ local ip = ipnode:value();
+ if ip then
+ local cmd = "ifconfig " .. name .. " " .. " inet " .. ip;
+ print("Run:" .. cmd)
+ print(exec_output(cmd));
+ end
+ end
+ end
+
+ config_iface(c, "lan0");
+ config_iface(c, "wlan0");
+ config_iface(c, "bridge0");
+
+end
+
+mpd = 0;
+
+function configure_mpd_link(c, path, bundle, link)
+ if mpd == 0 then
+ mpd = MPD:new(c, "127.0.0.1", 5005);
+ end
+
+-- local bundle = "PPP";
+-- local path = "interfaces.wan0.PPP";
+
+ mpd:config_bundle(path, bundle);
+ mpd:config_link(path, link, bundle);
+end
+
+function run_dhclient(c, iface)
+ local path = "interfaces." .. iface .. ".Static";
+
+ -- return if no iface.Static node.
+ if not c:getNode(path) then
+ return (nil);
+ end
+
+ -- return if Static mode not enabled.
+ if c:getNode(path):attr("enable") ~= "true" then
+ return (nil);
+ end
+
+ -- return if no DHCP enabled.
+ local dhcp = c:getNode(path .. ".dhcp");
+ if not dhcp or dhcp:attr("enable") ~= "true" then
+ return (nil);
+ end
+
+ -- Run dhclient
+ print("Run dhclient on " .. iface);
+ os.execute(string.format("kill `cat /var/run/dhclient.%s.pid`", iface));
+
+ -- Do not execute dhclient if interface is down
+ if exec_output("ifconfig -v " .. iface .." | grep 'status: active'") ~= "" then
+ os.execute(string.format("/sbin/dhclient -b %s", iface));
+ -- XXX, hack to "unplumb" iface if it was not up on boot
+ os.execute(string.format("ifconfig %s `ifconfig %s | grep 'ether '`", iface, iface));
+ end
+end
+
+
+function configure_wan(c)
+ -- TODO: auto enumerate wan links
+ --[[
+kldload ng_nat
+kldload ng_ipfw
+
+ngctl mkpeer ipfw: nat 60 out
+ngctl name ipfw:60 nat
+ngctl connect ipfw: nat: 61 in
+ngctl msg nat: setaliasaddr 192.168.101.204
+
+ipfw add 98 netgraph 61 all from any to any in via wan0
+ipfw add 99 netgraph 60 all from any to any out via wan0
+
+sysctl net.inet.ip.fw.one_pass=0
+ ]]
+
+ kldload({"ng_nat", "ng_ipfw"});
+ sysctl("net.inet.ip.fw.one_pass", 0);
+
+ local sub = "";
+ for _, sub in ipairs({"Static", "PPPoE", "PPP", "PTPP", "L2TP"}) do
+ print("sub=" .. sub);
+ local path = "interfaces.wan0." .. sub;
+ local ifnode = c:getNode(path);
+
+ if ifnode and ifnode:attr("enable") == "true" then
+ local subtype = c:getNode(path):attr("type");
+ print("subtype=" .. subtype);
+ if (subtype == "l2tp") then
+ -- TODO: multilink have different link names
+ elseif (subtype == "pppoe") then
+ kldload({"ng_pppoe"});
+ os.execute("sleep 1");
+ configure_mpd_link(c, path, sub, sub);
+ -- Add interface to route select logic
+ r.route:f(sub,
+ safeValue(c, path .. ".group", "WAN"),
+ safeValue(c, path .. ".cost", "1000") - 0,
+ "down",
+ "LINKDOWN")
+ elseif (subtype == "pptp") then
+ -- TODO: multilink have different link names
+ elseif (subtype == "modem") then
+ kldload({"umodem", "u3g"});
+ os.execute("sleep 1");
+ configure_mpd_link(c, path, sub, sub);
+ r.route:f(sub,
+ safeValue(c, path .. ".group", "WAN"),
+ safeValue(c, path .. ".cost", "1000") - 0,
+ "down",
+ "LINKDOWN")
+ elseif (subtype == "hw") then
+ local dev = c:getNode(path .. ".device"):value();
+ local dhcp = c:getNode(path .. ".dhcp");
+ local dhcpenabled = 0;
+ if dhcp and dhcp:attr("enable") == "true" then
+ dhcpenabled = true;
+ end
+
+ os.execute(string.format("ifconfig %s up", dev));
+ r.route:f(sub,
+ safeValue(c, path .. ".group", "WAN"),
+ safeValue(c, path .. ".cost", "1000") - 0,
+ "up",
+ "LINKDOWN")
+
+ local query = "cmd=event";
+ query = query .. "&state=up";
+ query = query .. "&iface=" .. urlEncode(dev);
+ query = query .. "&gw=" .. urlEncode(c:getNode(path .. ".gateway"):value());
+ query = query .. "&ip=" .. urlEncode(c:getNode(path .. ".ipaddr"):value());
+ query = query .. "&netmask=" .. urlEncode(c:getNode(path .. ".ipaddr"):value());
+ query = query .. "&dns1=" .. urlEncode(c:getNode(path .. ".dns1"):value());
+ query = query .. "&dns2=" .. urlEncode(c:getNode(path .. ".dns2"):value());
+
+ -- Call collector, to let him know about static config, and assign route+dns's
+ cmdline = "fetch -qo - \"http://127.0.0.1:8/event.xml?" .. query .. "\"";
+ print("Exec: " .. cmdline);
+ os.execute(cmdline);
+
+ -- Config static first
+ local ip = c:getNode(path .. ".ipaddr"):value();
+ local dhcp = c:getNode(path .. ".dhcp");
+ print("Run: \"ifconfig " .. dev .. " " .. ip .. "\"");
+ if os.execute(string.format("ifconfig %s %s", dev, ip)) ~= 0 then
+ print("\"ifconfig " .. dev .. " " .. ip .. "\" - failed");
+ end
+
+ run_dhclient(c, dev); -- if DHCP enabled.
+
+ -- XXX temporary FIX for wan0 with static address
+ -- if not dhcpenabled and dev == "wan0" then
+ os.execute(string.format("route add default %s",
+ c:getNode(path .. ".gateway"):value()));
+ -- end
+
+
+ local nat = c:getNode(path .. ".nat");
+ if nat and nat:attr("enable") == "true" then
+ local ip = c:getNode(path .. ".ipaddr"):value();
+ ip = ip:gsub("/%d+", "");
+ os.execute("ngctl mkpeer ipfw: nat 60 out");
+ os.execute("ngctl name ipfw:60 wan0nat");
+ os.execute("ngctl connect ipfw: wan0nat: 61 in");
+ os.execute("ngctl msg wan0nat: setaliasaddr " .. ip);
+
+ if dhcpenabled then
+ -- pass DHCP via iface
+ os.execute("ipfw add 96 allow all from any 67 to any 68 out via " .. dev);
+ os.execute("ipfw add 97 allow all from any 68 to any 67 out via " .. dev);
+ end
+ os.execute("ipfw add 98 netgraph 61 all from any to any in via " .. dev);
+ os.execute("ipfw add 99 netgraph 60 all from any to any out via " .. dev);
+ else
+ if dhcpenabled then
+ os.execute("ipfw delete 96");
+ os.execute("ipfw delete 97");
+ end
+ os.execute("ipfw delete 98");
+ os.execute("ipfw delete 99");
+ end
+ else
+ print("Unsupported interface type " .. subtype);
+ end
+ else
+ print("Skiping disabled iface " .. path);
+ end
+ end
+end
+
+dhcpd = 0;
+function start_dhcpd(c)
+ if c:getNode("dhcpd.instances.instance[1]"):attr("enable") == "true" then
+ if dhcpd == 0 then
+ dhcpd = DHCPD:new(c, "dhcpd.instances.instance[1]");
+ end
+ dhcpd:make_conf();
+ dhcpd:write();
+ print("Start DHCPD");
+ dhcpd:run();
+ end
+end
+
+function getopt(args, opts)
+ i=1;
+ while i < table.getn(arg) do
+ if arg[i]:match("^-") then
+ opts[arg[i]] = arg[i+1];
+ i = i + 1;
+ end
+ i = i + 1;
+ end
+ return (opts);
+end
+
+function update_board_info(c)
+ for _, oid in pairs({"device.vendor", "device.model", "device.revision", "soc.vendor", "soc.model"}) do
+ n = c:getOrCreateNode("info." .. oid);
+ n:value(sysctl("hw." .. oid));
+ if not n:value() then
+ n:value("__NO_DATA__");
+ end
+ print(tostring(oid) .. "=" .. n:value());
+ end
+end
+
+function safeValue(c, name, default)
+ node = c:getNode(name);
+ if not node then
+ if default then
+ return default;
+ else
+ return "";
+ end
+ end
+ return node:value();
+end
+
+function start_dnsmasq(c)
+ -- TODO: if DNS-Relay enabled
+ -- XXX: dnsmasq able to do DHCPD also
+ -- dhcp-range=[interface:<inter-face>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
+ -- # --domain=zrouter,192.168.0.100,192.168.0.200
+ -- # --dhcp-range=192.168.0.100,192.168.0.200,1h
+ -- # --dhcp-authoritative - don't wait for other DHCPDs
+ -- # --bogus-priv - NXDOMAIN for private nets
+ local_domain = "";
+ local_dhcp_range = "";
+ if c:getNode("dhcpd.instances.instance[1]"):attr("enable") == "true" then
+
+ dhcproot = "dhcpd.instances.instance[1].";
+ domain = safeValue(c, dhcproot .. "domain", "zrouter");
+ dltime = safeValue(c, dhcproot .. "default-lease-time", 3600);
+ mltime = safeValue(c, dhcproot .. "max-lease-time");
+ ranges = safeValue(c, dhcproot .. "range.start");
+ rangee = safeValue(c, dhcproot .. "range.end");
+
+ local_domain = " --domain=" .. domain .."," .. ranges .. "," .. rangee;
+ local_dhcp_range = " --dhcp-range=" .. ranges .. "," .. rangee .. "," .. dltime;
+
+ end
+ dnsmasq_cmd =
+ "/sbin/dnsmasq" ..
+ " -i bridge0" ..
+ local_domain ..
+ local_dhcp_range ..
+ " --dhcp-authoritative" ..
+ " --bogus-priv";
+
+ print("Start " .. dnsmasq_cmd);
+ os.execute(dnsmasq_cmd);
+end
+
+function start_hostapd(c)
+ if c:getNode("hostapd.instance[1]"):attr("enable") == "true" then
+ kldload({"wlan_xauth", "wlan_tkip", "wlan_ccmp"});
+ aproot = "hostapd.instance[1].";
+ driver = "bsd";
+ -- <ieee80211d>1</ieee80211d>
+ -- <country_code>UA</country_code>
+ channel = safeValue(c, aproot .. "channel", 6);
+ country_code = safeValue(c, aproot .. "country_code", "UA");
+ -- <interface>wlan0</interface>
+ interface = safeValue(c, aproot .. "interface", "wlan0");
+
+ commandline = string.format("ifconfig %s down",interface);
+ if os.execute(commandline) ~= 0 then
+ print("Exec: " .. commandline .. " - FAILED");
+ end
+ commandline = string.format(
+ "ifconfig %s country %s channel %s up",
+ interface, country_code, channel);
+ if os.execute(commandline) ~= 0 then
+ print("Exec: " .. commandline .. " - FAILED");
+ end
+ -- <macaddr_acl>0</macaddr_acl>
+ -- <auth_algs>1</auth_algs>
+ -- <debug>0</debug>
+ -- <hw_mode>g</hw_mode>
+ -- <ctrl_interface>/var/run/hostapd</ctrl_interface>
+ -- <ctrl_interface_group>wheel</ctrl_interface_group>
+ -- <ssid>zrouter</ssid>
+ ssid = safeValue(c, aproot .. "ssid", "zrouter");
+ -- <!-- Open -->
+ -- <wpa>0</wpa>
+ wpa = safeValue(c, aproot .. "wpa", 3);
+ -- <!-- WPA -->
+ -- <!-- <wpa>1</wpa> -->
+ -- <!-- RSN/WPA2 -->
+ -- <!-- <wpa>2</wpa> -->
+ -- <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+ wpa_key_mgmt = safeValue(c, aproot .. "wpa_key_mgmt", "WPA-PSK");
+ wpa_passphrase = safeValue(c, aproot .. "wpa_passphrase", "freebsdmall");
+ wpa_pairwise = safeValue(c, aproot .. "wpa_pairwise", "CCMP");
+ ctrl_interface = "/var/run/hostapd";
+
+ -- # TARGET
+ -- interface=wlan0
+ -- driver=bsd
+ -- ssid=CACHEBOY_11N_1
+ -- wpa=3
+ -- wpa_key_mgmt=WPA-PSK
+ -- wpa_passphrase=Sysinit891234
+ -- wpa_pairwise=CCMP
+ -- ctrl_interface=/var/run/hostapd
+ hostapd_conf = "/tmp/hostapd." .. interface ..".conf";
+
+ hostapd_conf_data =
+ "interface=" .. interface .. "\n" ..
+ "driver=" .. driver .. "\n" ..
+ "country_code=" .. country_code .. "\n" ..
+ "channel=" .. channel .. "\n" ..
+ "ssid=" .. ssid .. "\n" ..
+ "wpa=" .. wpa .. "\n" ..
+ "wpa_key_mgmt=" .. wpa_key_mgmt .. "\n" ..
+ "wpa_passphrase=" .. wpa_passphrase .. "\n" ..
+ "wpa_pairwise=" .. wpa_pairwise .. "\n" ..
+ "ctrl_interface=" .. ctrl_interface .. "\n";
+
+ local f = assert(io.open(hostapd_conf, "w"));
+ f:write(hostapd_conf_data);
+ f:close();
+
+ hostapd_cmd = "/usr/sbin/hostapd -B " .. hostapd_conf;
+
+ print("Start " .. hostapd_cmd);
+ os.execute(hostapd_cmd);
+
+ end
+end
+
+function start_igmp_fwd(c)
+ if not c:getNode("igmp.instance[1]") then
+ return;
+ end
+ if c:getNode("igmp.instance[1]"):attr("enable") == "true" then
+ upif = safeValue(c, aproot .. "up", "wan0");
+ downif = safeValue(c, aproot .. "down", "lan0");
+
+ cmd = "/etc/rc.d/ng_igmpproxy start " .. upif .. " " .. downif;
+
+ print("Start " .. cmd);
+ os.execute(cmd);
+ end
+end
+
+-- Globals
+config = {}; -- Unused now
+c = {}; -- XML tree from config.xml
+r = {}; -- Runtime varibles structure
+
+r.routes = {};
+r.routes["default"] = "127.0.0.1";
+r.routes["224.0.0.0/4"] = "-iface bridge0"
+r.tasks = {};
+r.tasks.step = 5; -- Seconds
+r.tasks.periodic = {};
+r.tasks.onetime = {}; -- At some time
+r.tasks.countdown= {}; -- when counter expired
+r.ver = {};
+
+opts = {};
+opts["-P"] = "/var/run/httpd.pid";
+
+if arg then
+ opts = getopt(arg, opts);
+end
+
+-- Check pidfile
+dofile("lib/pidfile.lua");
+pidfile(opts["-P"]);
+
+
+print("Parse config ...");
+c = Conf:new(load_file("config.xml"));
+
+update_board_info(c);
+read_zrouter_version(r);
+read_rc_conf(r);
+
+print("Initialize board ...");
+
+print("Initialize route select logic ...");
+r.route = ROUTE:new(c, 0);
+
+print("Enable LAN ports ...");
+os.execute("/etc/rc.d/switchctl enablelan");
+print("Init LAN ...");
+configure_lan(c);
+
+print("Start DHCP/DNS Relay ...");
+start_dnsmasq(c);
+-- start_dhcpd(c);
+
+-- print("Init AP");
+-- ap = HOSTAPD:new(c, 1);
+-- ap:run();
+
+print("Init AP ...");
+start_hostapd(c);
+
+print("Init IGMP/Multicast forwarding ...");
+start_igmp_fwd(c);
+
+os.execute("ipfw add 100 allow ip from any to any via lo0");
+-- os.execute("ipfw add 200 deny ip from any to 127.0.0.0/8");
+-- os.execute("ipfw add 300 deny ip from 127.0.0.0/8 to any");
+
+-- Hide Web-UI from WAN links
+os.execute("ipfw add 400 allow tcp from any to me 80 via lan0");
+os.execute("ipfw add 500 allow tcp from any to me 80 via bridge0");
+-- TODO: If not enabled WAN administration
+os.execute("ipfw add 600 deny tcp from any to me 80");
+-- check w/ ipfw NAT-ed packets
+sysctl("net.inet.ip.forwarding", 1);
+sysctl("net.inet.ip.fastforwarding", 1);
+sysctl("net.inet.tcp.blackhole", 2);
+sysctl("net.inet.udp.blackhole", 0);
+sysctl("net.inet.icmp.drop_redirect", 1);
+sysctl("net.inet.icmp.log_redirect", 0);
+sysctl("net.inet.ip.redirect", 0);
+sysctl("net.inet.ip.sourceroute", 0);
+sysctl("net.inet.ip.accept_sourceroute", 0);
+sysctl("net.inet.icmp.bmcastecho", 0);
+sysctl("net.inet.icmp.maskrepl", 0);
+sysctl("net.link.ether.inet.max_age", 30);
+sysctl("net.inet.ip.ttl", 226);
+sysctl("net.inet.tcp.drop_synfin", 1);
+sysctl("net.inet.tcp.syncookies", 1);
+-- sysctl("kern.ipc.somaxconn", 32768);
+-- sysctl("kern.maxfiles", 204800);
+-- sysctl("kern.maxfilesperproc", 200000);
+-- ??? -- sysctl("kern.ipc.nmbclusters", 524288);
+-- sysctl("kern.ipc.maxsockbuf", 2097152);
+sysctl("kern.random.sys.harvest.ethernet", 0);
+sysctl("kern.random.sys.harvest.interrupt", 0);
+-- sysctl("net.inet.ip.dummynet.io_fast", 1);
+-- sysctl("net.inet.ip.dummynet.max_chain_len", 2048);
+-- sysctl("net.inet.ip.dummynet.hash_size", 65535);
+-- sysctl("net.inet.ip.dummynet.pipe_slot_limit", 2048);
+-- ?? -- sysctl("net.inet.carp.preempt", 1);
+-- ?? -- sysctl("net.inet.carp.log", 2);
+-- ?? -- sysctl("kern.ipc.shmmax", 67108864);
+sysctl("net.inet.ip.intr_queue_maxlen", 8192);
+sysctl("net.inet.ip.fw.one_pass", 0);
+sysctl("net.inet.ip.portrange.randomized", 0);
+sysctl("net.inet.tcp.nolocaltimewait", 1);
+
+racoon = 0;
+if racoon == 0 then
+ racoon = RACOON:new(c);
+end
+
+-- WAN links tasks
+table.insert(r.tasks.countdown, { count=2, task=
+ function()
+ print("Init WAN links ...");
+ configure_wan(c);
+ return (true);
+ end
+ });
+-- IPSec links tasks
+table.insert(r.tasks.countdown, { count=10, task=
+ function()
+ print("Run racoon ...");
+ racoon:run();
+ return (true);
+ end
+ });
+
+print("Run server ...");
+start_server( c, config );
+
+
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/httpd.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/httpd.sh Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+
+cd /etc/www
+
+echo $$ > /var/run/httpd.sh.pid
+
+./httpd.lua > /var/log/httpd.sh.log 2>&1
+echo -n "./httpd.lua exit with status code $? at " >> /var/log/httpd.sh.log 2>&1
+date >> /var/log/httpd.sh.log 2>&1
+echo "./httpd.lua exit " > /dev/console
+exit 1
+
+while true; do
+ ./httpd.lua
+done
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/base64.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/base64.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,35 @@
+
+
+
+-- encoding
+function b64enc(data)
+ local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+ return ((data:gsub('.', function(x)
+ local r,b='',x:byte()
+ for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
+ if (#x < 6) then return '' end
+ local c=0
+ for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
+ return b:sub(c+1,c+1)
+ end)..({ '', '==', '=' })[#data%3+1])
+end
+
+-- decoding
+function b64dec(data)
+ local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+ data = string.gsub(data, '[^'..b..'=]', '')
+ return (data:gsub('.', function(x)
+ if (x == '=') then return '' end
+ local r,f='',(b:find(x)-1)
+ for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
+ return r;
+ end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
+ if (#x ~= 8) then return '' end
+ local c=0
+ for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
+ return string.char(c)
+ end))
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/bit.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/bit.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,29 @@
+function bit(p)
+ return 2 ^ (p - 1);
+ -- 1-based indexing
+end
+-- Typical call: if hasbit(x, bit(3)) then ...
+function hasbit(x, p)
+ return x % (p + p) >= p;
+end
+
+function setbit(x, p)
+ return hasbit(x, p) and x or x + p;
+end
+
+function clearbit(x, p)
+ return hasbit(x, p) and x - p or x;
+end
+
+-- &(0x12345678 & 0xfffff000) = 0x12345000
+function andL(x, y)
+ local o = 0;
+
+ for i = 1,32,1 do
+ if hasbit(x, bit(i)) and hasbit(y, bit(i)) then
+ o = o + bit(i);
+ end
+ end
+
+ return (o);
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/conf.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/conf.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,158 @@
+-----------------------------------
+----------- Conf Class ------------
+-----------------------------------
+Conf = {};
+local mt = {};
+
+function Conf:new(s)
+ return setmetatable({ tree = s or '' }, mt)
+end
+
+function Conf:gettree()
+ return (self.tree);
+end
+
+function Conf:getNodeValue(path)
+ local node = self:getNode(path);
+ if type(node) == "table" then
+ return (node:value());
+ end
+ return (nil);
+end
+
+function Conf:getNode(path)
+ local function getNodeL(node, lpath)
+ local match, name, rpath, id = nil;
+ local matched = 0;
+
+ if not node then return (nil) end
+ if (not lpath) or (string.len(lpath) == 0) then
+ return (node);
+ end
+
+ match, _, name, _, rpath = string.find(lpath, "^([%w%_%-%[%]]+)(%.*)(%S*)$");
+ if not match then
+ print("Wrong lpath " .. lpath);
+ return (nil);
+ end
+
+ rmatch, _, idname, id = string.find(name, "^([%w%_%-]+)%[(%d+)%]$");
+ if rmatch then
+ name = idname;
+ end
+
+ if not name then
+ print("Empty name");
+ return (nil);
+ end
+
+ if node._children then
+ for _, v in ipairs(node._children) do
+ if v._type == "ELEMENT" and v._name == name then
+ matched = matched + 1;
+ if (not id or (matched == tonumber(id))) then
+ if string.len(rpath) > 0 then
+ return getNodeL(v, rpath);
+ end
+ return (v);
+ end
+ end
+ end
+ end
+ return (nil);
+ end
+
+ local ret = getNodeL(self.tree, path);
+ return (Node:new(ret, path));
+end
+
+-- node = { _name = <Element Name>,
+-- _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD,
+-- _attr = { Node attributes - see callback API },
+-- _parent = <Parent Node>
+-- _children = { List of child nodes - ROOT/NODE only }
+-- }
+
+function createNode(_name, _type, _attr, _children, _parent)
+ -- TODO: check for "^(ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD)$"
+ if not _name or not _type then
+ print(_name or "(no name)", _type or "(no type)");
+
+ return (nil);
+ end
+
+ local t = {};
+ t._name = _name;
+ t._type = _type;
+ t._attr = _attr or {};
+ t._parent = _parent;
+ t._children = _children or {};
+ return (t);
+end
+
+function attachNode(parent, node)
+ if not parent or not node then
+ return (nil);
+ end
+
+ if not parent._children then
+ parent._children = {};
+ end
+
+ table.insert(parent._children, node);
+ node._parent = parent;
+
+ return (node);
+end
+
+function Conf:getOrCreateNode(path)
+ local node = self:getNode(path);
+ if node then
+ return (node);
+ end
+
+ node = self.tree;
+ for part in string.gmatch(path, "([^\.]+)%.?") do
+ local rmatch, _, idname, id = string.find(part, "^([%w%_%-]+)%[(%d+)%]$");
+ if rmatch then
+ part = idname;
+ end
+
+ local matched = 0;
+ if type(node) == "table" and type(node._children) == "table" then
+ for _, v in ipairs(node._children) do
+
+ if v._type == "ELEMENT" and v._name == part then
+ matched = matched + 1;
+
+ if id then
+ if id == matched then
+ node = v;
+ break;
+ end
+ else
+ node = v;
+ break;
+ end
+ end
+ end
+ end
+
+ if matched == 0 or (id and matched < tonumber(id)) then
+ local new = createNode(part, "ELEMENT");
+ attachNode(node, new);
+ node = new;
+ end
+ end
+ return (Node:new(node, path));
+end
+
+function Conf:get(path)
+ print(tostring(self.tree), path);
+ return (path);
+end
+
+mt.__index = Conf;
+-----------------------------------
+-------- End of Conf Class --------
+-----------------------------------
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/dhcpd.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/dhcpd.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,106 @@
+--[[
+option domain-name "fugue.com";
+option domain-name-servers toccata.fugue.com;
+
+option subnet-mask 255.255.255.224;
+default-lease-time 600;
+max-lease-time 7200;
+
+
+subnet 192.5.5.0 netmask 255.255.255.224 {
+ range 192.5.5.26 192.5.5.30;
+ option name-servers bb.home.vix.com, gw.home.vix.com;
+ option domain-name "vix.com";
+ option routers 192.5.5.1;
+ option subnet-mask 255.255.255.224;
+ option broadcast-address 192.5.5.31;
+ default-lease-time 600;
+ max-lease-time 7200;
+}
+
+host fantasia {
+ hardware ethernet 08:00:07:26:c0:a5;
+ fixed-address fantasia.fugue.com;
+}
+]]
+
+require("ipcalc");
+
+DHCPD = {};
+local mt = {};
+
+--DHCPD.instances.instance[1]
+
+
+function DHCPD:new(c, path, debug)
+ t = {};
+ t.path = path;
+ t.c = c;
+ t.iface = c:getNode(path .. "." .. "interface"):value()
+ t.configfile = "/tmp/dhcpd_" .. t.iface .. ".conf";
+ t.pidfile = "/tmp/dhcpd_" .. t.iface .. ".pid";
+ t.debug = debug;
+ return setmetatable(t, mt);
+end
+
+function DHCPD:make_conf()
+
+ self.get = function (var ) return self.c:getNode(self.path .. "." .. var):value() end;
+ self.attr = function (var, attr) return self.c:getNode(self.path .. "." .. var):attr(attr) end;
+ self.conf_data = "";
+
+ local function a(txt)
+ if not txt then
+ return (nil);
+ end
+ self.conf_data = self.conf_data .. txt .. "\n";
+ if self.debug then print(txt); end
+ end
+
+
+
+
+ local function perhost(name, macaddr, ip)
+ return "host " .. name .." {\n\thardware ethernet " .. macaddr ..
+ ";\n\tfixed-address " .. ip ..";\n}\n";
+ end
+-- for i = 1,16,1 do
+-- -- TODO: static entrys
+-- end
+
+ local if_ipaddr = self.c:getNode("interfaces." .. self.iface .. ".ipaddr"):value();
+ local r = cidr_to_net(if_ipaddr);
+ a("option domain-name \"".. self.get("domain") .."\";");
+ a("option domain-name-servers " .. r.ip ..";");
+ a("default-lease-time " .. self.get("default-lease-time") ..";");
+ a("max-lease-time ".. self.get("max-lease-time") ..";");
+ a("subnet " .. r.net .." netmask " .. r.mask .." {");
+ a("\trange " .. self.get("range.start") .. " " .. self.get("range.end") ..";");
+ a("\toption routers " .. r.ip ..";");
+ a("\toption broadcast-address " .. r.broadcast ..";");
+ a("}");
+
+end
+
+function DHCPD:write()
+
+ local f = assert(io.open(self.configfile, "w"));
+ f:write(self.conf_data);
+ f:close();
+end
+
+function DHCPD:run()
+
+ os.execute("mkdir -p /var/run/");
+ os.execute("mkdir -p /var/db/");
+ os.execute("touch /var/db/dhcpd.leases");
+ os.execute("/sbin/dhcpd -lf /var/db/dhcpd.leases -cf " .. self.configfile .. " " .. self.iface);
+end
+
+function DHCPD:stop()
+
+ os.execute("kill `cat /var/run/dhcpd.pid`");
+end
+
+mt.__index = DHCPD;
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/handler.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/handler.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,305 @@
+---
+-- Overview:
+-- =========
+-- Standard XML event handler(s) for XML parser module (xml.lua)
+--
+-- Features:
+-- =========
+-- printHandler - Generate XML event trace
+-- domHandler - Generate DOM-like node tree
+-- simpleTreeHandler - Generate 'simple' node tree
+--
+-- API:
+-- ====
+-- Must be called as handler function from xmlParser
+-- and implement XML event callbacks (see xmlParser.lua
+-- for callback API definition)
+--
+-- printHandler:
+-- -------------
+--
+-- printHandler prints event trace for debugging
+--
+-- domHandler:
+-- -----------
+--
+-- domHandler generates a DOM-like node tree structure with
+-- a single ROOT node parent - each node is a table comprising
+-- fields below.
+--
+-- node = { _name = <Element Name>,
+-- _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD,
+-- _attr = { Node attributes - see callback API },
+-- _parent = <Parent Node>
+-- _children = { List of child nodes - ROOT/NODE only }
+-- }
+--
+-- The dom structure is capable of representing any valid XML document
+--
+-- simpleTreeHandler
+-- -----------------
+--
+-- simpleTreeHandler is a simplified handler which attempts
+-- to generate a more 'natural' table based structure which
+-- supports many common XML formats.
+--
+-- The XML tree structure is mapped directly into a recursive
+-- table structure with node names as keys and child elements
+-- as either a table of values or directly as a string value
+-- for text. Where there is only a single child element this
+-- is inserted as a named key - if there are multiple
+-- elements these are inserted as a vector (in some cases it
+-- may be preferable to always insert elements as a vector
+-- which can be specified on a per element basis in the
+-- options). Attributes are inserted as a child element with
+-- a key of '_attr'.
+--
+-- Only Tag/Text & CDATA elements are processed - all others
+-- are ignored.
+--
+-- This format has some limitations - primarily
+--
+-- * Mixed-Content behaves unpredictably - the relationship
+-- between text elements and embedded tags is lost and
+-- multiple levels of mixed content does not work
+-- * If a leaf element has both a text element and attributes
+-- then the text must be accessed through a vector (to
+-- provide a container for the attribute)
+--
+-- In general however this format is relatively useful.
+--
+-- It is much easier to understand by running some test
+-- data through 'textxml.lua -simpletree' than to read this)
+--
+-- Options
+-- =======
+-- simpleTreeHandler.options.noReduce = { <tag> = bool,.. }
+--
+-- - Nodes not to reduce children vector even if only
+-- one child
+--
+-- domHandler.options.(comment|pi|dtd|decl)Node = bool
+--
+-- - Include/exclude given node types
+--
+-- Usage
+-- =====
+-- Pased as delegate in xmlParser constructor and called
+-- as callback by xmlParser:parse(xml) method.
+--
+-- See textxml.lua for examples
+-- License:
+-- ========
+--
+-- This code is freely distributable under the terms of the Lua license
+-- (<a href="http://www.lua.org/copyright.html">http://www.lua.org/copyright.html</a>)
+--
+-- History
+-- =======
+-- $Id: handler.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+-- $Log: handler.lua,v $
+-- Revision 1.1.1.1 2001/11/28 06:11:33 paulc
+-- Initial Import
+-- at author Paul Chakravarti (paulc at passtheaardvark.com)<p/>
+
+
+---Handler to generate a string prepresentation of a table
+--Convenience function for printHandler (Does not support recursive tables).
+-- at param t Table to be parsed
+-- at returns Returns a string representation of table
+function showTable(t)
+ local sep = ''
+ local res = ''
+ if type(t) ~= 'table' then
+ return t
+ end
+ for k,v in pairs(t) do
+ if type(v) == 'table' then
+ v = showTable(v)
+ end
+ res = res .. sep .. string.format("%s=%s",k,v)
+ sep = ','
+ end
+ res = '{'..res..'}'
+ return res
+end
+
+---Handler to generate a simple event trace
+printHandler = function()
+ local obj = {}
+ obj.starttag = function(self,t,a,s,e)
+ io.write("Start : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io.write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ obj.endtag = function(self,t,s,e)
+ io.write("End : "..t.."\n")
+ end
+ obj.text = function(self,t,s,e)
+ io.write("Text : "..t.."\n")
+ end
+ obj.cdata = function(self,t,s,e)
+ io.write("CDATA : "..t.."\n")
+ end
+ obj.comment = function(self,t,s,e)
+ io.write("Comment : "..t.."\n")
+ end
+ obj.dtd = function(self,t,a,s,e)
+ io.write("DTD : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io.write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ obj.pi = function(self,t,a,s,e)
+ io.write("PI : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io. write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ obj.decl = function(self,t,a,s,e)
+ io.write("XML Decl : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io.write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ return obj
+end
+
+---Handler to generate a lua table from a XML content string
+function simpleTreeHandler()
+ local obj = {}
+
+ obj.root = {}
+ obj.stack = {obj.root;n=1}
+ obj.options = {noreduce = {}}
+
+ obj.reduce = function(self,node,key,parent)
+ -- Recursively remove redundant vectors for nodes
+ -- with single child elements
+ for k,v in pairs(node) do
+ if type(v) == 'table' then
+ self:reduce(v,k,node)
+ end
+ end
+ if table.getn(node) == 1 and not self.options.noreduce[key] and
+ node._attr == nil then
+ parent[key] = node[1]
+ else
+ node.n = nil
+ end
+ end
+
+ obj.starttag = function(self,t,a)
+ local node = {}
+ if self.parseAttributes == true then
+ node._attr=a
+ end
+
+ local current = self.stack[table.getn(self.stack)]
+ if current[t] then
+ table.insert(current[t],node)
+ else
+ current[t] = {node;n=1}
+ end
+ table.insert(self.stack,node)
+ end
+
+ obj.endtag = function(self,t,s)
+ local current = self.stack[table.getn(self.stack)]
+ local prev = self.stack[table.getn(self.stack)-1]
+ if not prev[t] then
+ error("XML Error - Unmatched Tag ["..s..":"..t.."]\n")
+ end
+ if prev == self.root then
+ -- Once parsing complete recursively reduce tree
+ self:reduce(prev,nil,nil)
+ end
+ table.remove(self.stack)
+ end
+
+ obj.text = function(self,t)
+ local current = self.stack[table.getn(self.stack)]
+ table.insert(current,t)
+ end
+
+ obj.cdata = obj.text
+
+ return obj
+end
+
+--- domHandler
+function domHandler()
+ local obj = {}
+ obj.options = {commentNode=1,piNode=1,dtdNode=1,declNode=1}
+ obj.root = { _children = {n=0}, _type = "ROOT" }
+ obj.current = obj.root
+ obj.starttag = function(self,t,a)
+ local node = { _type = 'ELEMENT',
+ _name = t,
+ _attr = a,
+ _parent = self.current,
+ _children = {n=0} }
+ table.insert(self.current._children,node)
+ self.current = node
+ end
+ obj.endtag = function(self,t,s)
+ if t ~= self.current._name then
+ error("XML Error - Unmatched Tag ["..s..":"..t.."]\n")
+ end
+ self.current = self.current._parent
+ end
+ obj.text = function(self,t)
+ local node = { _type = "TEXT",
+ _parent = self.current,
+ _text = t }
+ table.insert(self.current._children,node)
+ end
+ obj.comment = function(self,t)
+ if self.options.commentNode then
+ local node = { _type = "COMMENT",
+ _parent = self.current,
+ _text = t }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.pi = function(self,t,a)
+ if self.options.piNode then
+ local node = { _type = "PI",
+ _name = t,
+ _attr = a,
+ _parent = self.current }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.decl = function(self,t,a)
+ if self.options.declNode then
+ local node = { _type = "DECL",
+ _name = t,
+ _attr = a,
+ _parent = self.current }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.dtd = function(self,t,a)
+ if self.options.dtdNode then
+ local node = { _type = "DTD",
+ _name = t,
+ _attr = a,
+ _parent = self.current }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.cdata = obj.text
+ return obj
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/hostapd.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/hostapd.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,143 @@
+--[[
+ieee80211d=1
+country_code=UA
+interface=wlan0
+macaddr_acl=0
+auth_algs=1
+debug=1
+hw_mode=g
+ctrl_interface=/var/run/hostapd
+ctrl_interface_group=wheel
+ssid=freebsdap
+wpa=2
+wpa_passphrase=freebsdmall
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP TKIP
+
+<hostapd>
+ <instance id="0" enable="true">
+ <ieee80211d>1</ieee80211d>
+ <country_code>UA</country_code>
+ <interface>wlan0</interface>
+ <macaddr_acl>0</macaddr_acl>
+ <auth_algs>1</auth_algs>
+ <debug>0</debug>
+ <hw_mode>g</hw_mode>
+ <ctrl_interface>/var/run/hostapd</ctrl_interface>
+ <ctrl_interface_group>wheel</ctrl_interface_group>
+ <ssid>DIR-620</ssid>
+ <!-- Open -->
+ <wpa>0</wpa>
+ <!-- WPA -->
+ <!-- <wpa>1</wpa> -->
+ <!-- RSN/WPA2 -->
+ <!-- <wpa>2</wpa> -->
+ </instance>
+ <instance id="1" enable="false">
+ <ieee80211d>1</ieee80211d>
+ <country_code>UA</country_code>
+ <interface>wlan0</interface>
+ <macaddr_acl>0</macaddr_acl>
+ <auth_algs>1</auth_algs>
+ <debug>0</debug>
+ <hw_mode>g</hw_mode>
+ <ctrl_interface>/var/run/hostapd</ctrl_interface>
+ <ctrl_interface_group>wheel</ctrl_interface_group>
+ <ssid>DIR-620</ssid>
+ <!-- WPA -->
+ <!-- <wpa>1</wpa> -->
+ <!-- RSN/WPA2 -->
+ <wpa>2</wpa>
+ <wpa_passphrase>freebsdmall</wpa_passphrase>
+ <wpa_key_mgmt>WPA-PSK</wpa_key_mgmt>
+ <wpa_pairwise>CCMP TKIP</wpa_pairwise>
+ </instance>
+</hostapd>
+
+]]
+
+HOSTAPD = {};
+local mt = {};
+
+--hostapd.instance[1]
+
+
+function HOSTAPD:new(c, debug)
+ t = {};
+ t.c = c;
+ t.debug = debug;
+ t.configfile = {};
+ t.conf_data = {};
+ t.pidfile = "/var/run/hostapd.pid";
+ return setmetatable(t, mt);
+end
+
+function HOSTAPD:make_conf(i)
+
+ if self.debug == 1 then print("HOSTAPD:make_conf(".. tostring(i) .. ")"); end
+
+ local path = "hostapd.instance[" .. i .. "]";
+
+ self.conf_data[i] = "";
+
+ local function a(txt)
+ if not txt then
+ return (nil);
+ end
+ self.conf_data[i] = self.conf_data[i] .. txt .. "\n";
+ if self.debug then print(txt); end
+ end
+
+ local iface = self.c:getNode(path .. ".interface"):value();
+ self.configfile[i] = "/tmp/hostapd_" .. iface .. ".conf";
+
+ a("ieee80211d=1");
+ a("country_code=UA");
+ a("interface=" .. iface);
+ a("macaddr_acl=0");
+ a("auth_algs=1");
+ a("debug=0");
+ a("hw_mode=g");
+ a("ctrl_interface=/var/run/hostapd");
+ a("ctrl_interface_group=wheel");
+ a("ssid=" .. self.c:getNode(path .. ".ssid"):value() .. "");
+ -- TODO: crypto support
+ a("wpa=2");
+ a("wpa_passphrase=freebsdmall");
+ a("wpa_key_mgmt=WPA-PSK");
+ a("wpa_pairwise=CCMP");
+
+end
+
+function HOSTAPD:write(i)
+
+ local f = assert(io.open(self.configfile[i], "w"));
+ f:write(self.conf_data[i]);
+ f:close();
+end
+
+function HOSTAPD:run()
+ local configs = "";
+ local i;
+ for i = 1,8,1 do
+ local vap = self.c:getNode("hostapd.instance[" .. i .. "]");
+ if vap and vap:attr("enable") == "true" then
+ if self.debug == 1 then print("CALL self.make_conf(".. tostring(i) .. ")"); end
+ self:make_conf(i);
+ if self.debug == 1 then print("CALL self.write(".. tostring(i) .. ")"); end
+ self:write(i);
+ configs = configs .. " " .. self.configfile[i];
+ end
+ end
+
+ os.execute("mkdir -p /var/run/");
+ os.execute("/usr/sbin/hostapd -B -P " .. self.pidfile .. " " .. configs);
+end
+
+function HOSTAPD:stop()
+
+ os.execute("kill `cat " .. self.pidfile .."`");
+end
+
+mt.__index = HOSTAPD;
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/ipcalc.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/ipcalc.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,58 @@
+require("bit");
+
+function bits_to_hostmask(b)
+ return (2 ^ (32-b) - 1);
+end
+
+function bits_to_netmask(b)
+ return ((2 ^ 32 - 1) - bits_to_hostmask(b));
+end
+
+
+function cidr_to_net(cidr)
+ local r = {};
+ r.cidr = cidr;
+
+ local function dotted(i)
+ local l1,l2,l3,r1,r2,r3,r4;
+ r1 = i % 256; l1 = i / 256;
+ r2 = l1 % 256; l2 = l1 / 256;
+ r3 = l2 % 256; l3 = l2 / 256;
+ r4 = l3 % 256;
+ return string.format("%d.%d.%d.%d", r4, r3, r2, r1);
+ end
+
+ local function toint(i1, i2, i3, i4)
+ return
+ ((tonumber(i1) * (2^24)) +
+ (tonumber(i2) * (2^16)) +
+ (tonumber(i3) * ( 2^8)) +
+ (tonumber(i4) ));
+ end
+
+ local i1, i2, i3, i4;
+
+ i1, i2, i3, i4, r.bits = string.match(cidr, "^(%d+)%.(%d+)%.(%d+)%.(%d+)%/(%d+)$");
+
+ if r.bits then
+ r.ip = toint(i1, i2, i3, i4);
+ else
+ local i1, i2, i3, i4, m1, m2, m3, m4 = string.match(cidr,
+ "^(%d+)%.(%d+)%.(%d+)%.(%d+)%/(%d+)%.(%d+)%.(%d+)%.(%d+)$");
+ if m4 then
+ r.ip = toint(i1, i2, i3, i4);
+ r.net = toint(m1, m2, m3, m4);
+ else
+ return nil, "Failed to parse";
+ end
+ end
+
+ r.mask = dotted( bits_to_netmask (r.bits));
+ r.net = dotted(andL(r.ip, bits_to_netmask (r.bits)));
+ r.host = dotted(andL(r.ip, bits_to_hostmask(r.bits)));
+ r.broadcast = dotted(andL(r.ip, bits_to_netmask (r.bits)) + (2 ^ (32-r.bits) - 1) );
+ r.ip = dotted( r.ip);
+
+ return r;
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/ltn12.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/ltn12.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,292 @@
+-----------------------------------------------------------------------------
+-- LTN12 - Filters, sources, sinks and pumps.
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module
+-----------------------------------------------------------------------------
+local string = require("string")
+local table = require("table")
+local base = _G
+module("ltn12")
+
+filter = {}
+source = {}
+sink = {}
+pump = {}
+
+-- 2048 seems to be better in windows...
+BLOCKSIZE = 2048
+_VERSION = "LTN12 1.0.1"
+
+-----------------------------------------------------------------------------
+-- Filter stuff
+-----------------------------------------------------------------------------
+-- returns a high level filter that cycles a low-level filter
+function filter.cycle(low, ctx, extra)
+ base.assert(low)
+ return function(chunk)
+ local ret
+ ret, ctx = low(ctx, chunk, extra)
+ return ret
+ end
+end
+
+-- chains a bunch of filters together
+-- (thanks to Wim Couwenberg)
+function filter.chain(...)
+ local n = table.getn(arg)
+ local top, index = 1, 1
+ local retry = ""
+ return function(chunk)
+ retry = chunk and retry
+ while true do
+ if index == top then
+ chunk = arg[index](chunk)
+ if chunk == "" or top == n then return chunk
+ elseif chunk then index = index + 1
+ else
+ top = top+1
+ index = top
+ end
+ else
+ chunk = arg[index](chunk or "")
+ if chunk == "" then
+ index = index - 1
+ chunk = retry
+ elseif chunk then
+ if index == n then return chunk
+ else index = index + 1 end
+ else base.error("filter returned inappropriate nil") end
+ end
+ end
+ end
+end
+
+-----------------------------------------------------------------------------
+-- Source stuff
+-----------------------------------------------------------------------------
+-- create an empty source
+local function empty()
+ return nil
+end
+
+function source.empty()
+ return empty
+end
+
+-- returns a source that just outputs an error
+function source.error(err)
+ return function()
+ return nil, err
+ end
+end
+
+-- creates a file source
+function source.file(handle, io_err)
+ if handle then
+ return function()
+ local chunk = handle:read(BLOCKSIZE)
+ if not chunk then handle:close() end
+ return chunk
+ end
+ else return source.error(io_err or "unable to open file") end
+end
+
+-- turns a fancy source into a simple source
+function source.simplify(src)
+ base.assert(src)
+ return function()
+ local chunk, err_or_new = src()
+ src = err_or_new or src
+ if not chunk then return nil, err_or_new
+ else return chunk end
+ end
+end
+
+-- creates string source
+function source.string(s)
+ if s then
+ local i = 1
+ return function()
+ local chunk = string.sub(s, i, i+BLOCKSIZE-1)
+ i = i + BLOCKSIZE
+ if chunk ~= "" then return chunk
+ else return nil end
+ end
+ else return source.empty() end
+end
+
+-- creates rewindable source
+function source.rewind(src)
+ base.assert(src)
+ local t = {}
+ return function(chunk)
+ if not chunk then
+ chunk = table.remove(t)
+ if not chunk then return src()
+ else return chunk end
+ else
+ table.insert(t, chunk)
+ end
+ end
+end
+
+function source.chain(src, f)
+ base.assert(src and f)
+ local last_in, last_out = "", ""
+ local state = "feeding"
+ local err
+ return function()
+ if not last_out then
+ base.error('source is empty!', 2)
+ end
+ while true do
+ if state == "feeding" then
+ last_in, err = src()
+ if err then return nil, err end
+ last_out = f(last_in)
+ if not last_out then
+ if last_in then
+ base.error('filter returned inappropriate nil')
+ else
+ return nil
+ end
+ elseif last_out ~= "" then
+ state = "eating"
+ if last_in then last_in = "" end
+ return last_out
+ end
+ else
+ last_out = f(last_in)
+ if last_out == "" then
+ if last_in == "" then
+ state = "feeding"
+ else
+ base.error('filter returned ""')
+ end
+ elseif not last_out then
+ if last_in then
+ base.error('filter returned inappropriate nil')
+ else
+ return nil
+ end
+ else
+ return last_out
+ end
+ end
+ end
+ end
+end
+
+-- creates a source that produces contents of several sources, one after the
+-- other, as if they were concatenated
+-- (thanks to Wim Couwenberg)
+function source.cat(...)
+ local src = table.remove(arg, 1)
+ return function()
+ while src do
+ local chunk, err = src()
+ if chunk then return chunk end
+ if err then return nil, err end
+ src = table.remove(arg, 1)
+ end
+ end
+end
+
+-----------------------------------------------------------------------------
+-- Sink stuff
+-----------------------------------------------------------------------------
+-- creates a sink that stores into a table
+function sink.table(t)
+ t = t or {}
+ local f = function(chunk, err)
+ if chunk then table.insert(t, chunk) end
+ return 1
+ end
+ return f, t
+end
+
+-- turns a fancy sink into a simple sink
+function sink.simplify(snk)
+ base.assert(snk)
+ return function(chunk, err)
+ local ret, err_or_new = snk(chunk, err)
+ if not ret then return nil, err_or_new end
+ snk = err_or_new or snk
+ return 1
+ end
+end
+
+-- creates a file sink
+function sink.file(handle, io_err)
+ if handle then
+ return function(chunk, err)
+ if not chunk then
+ handle:close()
+ return 1
+ else return handle:write(chunk) end
+ end
+ else return sink.error(io_err or "unable to open file") end
+end
+
+-- creates a sink that discards data
+local function null()
+ return 1
+end
+
+function sink.null()
+ return null
+end
+
+-- creates a sink that just returns an error
+function sink.error(err)
+ return function()
+ return nil, err
+ end
+end
+
+-- chains a sink with a filter
+function sink.chain(f, snk)
+ base.assert(f and snk)
+ return function(chunk, err)
+ if chunk ~= "" then
+ local filtered = f(chunk)
+ local done = chunk and ""
+ while true do
+ local ret, snkerr = snk(filtered, err)
+ if not ret then return nil, snkerr end
+ if filtered == done then return 1 end
+ filtered = f(done)
+ end
+ else return 1 end
+ end
+end
+
+-----------------------------------------------------------------------------
+-- Pump stuff
+-----------------------------------------------------------------------------
+-- pumps one chunk from the source to the sink
+function pump.step(src, snk)
+ local chunk, src_err = src()
+ local ret, snk_err = snk(chunk, src_err)
+ if chunk and ret then return 1
+ else return nil, src_err or snk_err end
+end
+
+-- pumps all data from a source to a sink, using a step function
+function pump.all(src, snk, step)
+ base.assert(src and snk)
+ step = step or pump.step
+ while true do
+ local ret, err = step(src, snk)
+ if not ret then
+ if err then return nil, err
+ else return 1 end
+ end
+ end
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/mime.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/mime.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,87 @@
+-----------------------------------------------------------------------------
+-- MIME support for the Lua language.
+-- Author: Diego Nehab
+-- Conforming to RFCs 2045-2049
+-- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local ltn12 = require("ltn12")
+local mime = require("mime.core")
+local io = require("io")
+local string = require("string")
+module("mime")
+
+-- encode, decode and wrap algorithm tables
+encodet = {}
+decodet = {}
+wrapt = {}
+
+-- creates a function that chooses a filter by name from a given table
+local function choose(table)
+ return function(name, opt1, opt2)
+ if base.type(name) ~= "string" then
+ name, opt1, opt2 = "default", name, opt1
+ end
+ local f = table[name or "nil"]
+ if not f then
+ base.error("unknown key (" .. base.tostring(name) .. ")", 3)
+ else return f(opt1, opt2) end
+ end
+end
+
+-- define the encoding filters
+encodet['base64'] = function()
+ return ltn12.filter.cycle(b64, "")
+end
+
+encodet['quoted-printable'] = function(mode)
+ return ltn12.filter.cycle(qp, "",
+ (mode == "binary") and "=0D=0A" or "\r\n")
+end
+
+-- define the decoding filters
+decodet['base64'] = function()
+ return ltn12.filter.cycle(unb64, "")
+end
+
+decodet['quoted-printable'] = function()
+ return ltn12.filter.cycle(unqp, "")
+end
+
+local function format(chunk)
+ if chunk then
+ if chunk == "" then return "''"
+ else return string.len(chunk) end
+ else return "nil" end
+end
+
+-- define the line-wrap filters
+wrapt['text'] = function(length)
+ length = length or 76
+ return ltn12.filter.cycle(wrp, length, length)
+end
+wrapt['base64'] = wrapt['text']
+wrapt['default'] = wrapt['text']
+
+wrapt['quoted-printable'] = function()
+ return ltn12.filter.cycle(qpwrp, 76, 76)
+end
+
+-- function that choose the encoding, decoding or wrap algorithm
+encode = choose(encodet)
+decode = choose(decodet)
+wrap = choose(wrapt)
+
+-- define the end-of-line normalization filter
+function normalize(marker)
+ return ltn12.filter.cycle(eol, 0, marker)
+end
+
+-- high level stuffing filter
+function stuff()
+ return ltn12.filter.cycle(dot, 2)
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/mpd.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/mpd.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,315 @@
+-----------------------------------
+----------- MPD Class ------------
+-----------------------------------
+--[[
+
+create bundle static B1
+bundle B1
+
+set bundle links L1
+
+set iface addrs 1.1.1.1 2.2.2.2
+set iface route default
+set iface enable on-demand
+set iface idle 900
+set iface enable nat
+set iface up-script /etc/mpd5-up.sh
+set iface down-script /etc/mpd5-down.sh
+
+set ipcp ranges 0.0.0.0/0 0.0.0.0/0
+set ipcp enable req-pri-dns
+set ipcp enable req-sec-dns
+
+open iface
+
+
+
+create link static L1 modem
+create link static L1 pppoe
+create link static L1 pptp
+create link static L1 ltp
+
+set auth authname adbrd****@dsl.ukrtel.net
+set auth password *******
+
+set modem device /dev/cuaU0.0
+set modem var $DialPrefix "DT"
+set modem var $Telephone "#777"
+set modem var $TryPPPEarly "yes"
+set modem var $InitString "+CGDCONT=1,\"IP\",\"internet\""
+set modem script DialPeer
+set modem idle-script Ringback
+set modem watch -cd
+
+set pppoe iface nfe0
+set pppoe service ""
+
+set pptp self 10.1.3.3
+set pptp peer 10.1.0.1
+set pptp disable windowing
+
+set l2tp peer 10.10.10.10
+
+set link disable chap pap
+set link accept chap pap
+set link action bundle B1
+set link enable incoming
+set link max-redial 0
+set link mtu 1460
+set link keep-alive 10 60
+set link bandwidth 14194304
+
+open
+
+
+
+
+
+
+]]
+
+--require("sleep");
+
+MPD = {};
+mt = {};
+
+function MPD:new(tree, host, port, debug)
+ local t = {};
+ if not host or not port then
+ print("No host or port");
+ return (nil);
+ end
+
+-- t.socket = socket.connect(host, port);
+-- if not t.socket then
+-- print("Can't connect to " .. host .. ":" .. port);
+-- return (nil);
+-- end
+ t.host = host;
+ t.port = port;
+ t.c = tree;
+ t.debug = 1;
+ return setmetatable(t, mt);
+end
+
+function MPD:msg(s, wait)
+
+ if self.debug then print("DEBUG MPD:msg: " .. s); end
+ self.socket:settimeout(0.1);
+ self.socket:send(s .. "\n");
+
+ local err = nil;
+ local ret = "";
+-- while not err do
+ local data, err = self.socket:receive("*a");
+ ret = ret .. (data or "");
+-- end
+ if self.debug then print("DEBUG MPD:msg:return = [[" .. ret .. "]]"); end
+
+ return (ret);
+end
+
+function MPD:config_bundle(path, bundle)
+ local pathl = path .. ".";
+ local node;
+
+ self.socket = socket.connect(self.host, self.port);
+ if not self.socket then
+ print("Can't connect to " .. self.host .. ":" .. self.port);
+ return (nil);
+ end
+ -- Create or select bundle
+ self:msg("create bundle static " .. bundle);
+ self:msg("bundle " .. bundle);
+
+ -- Multilink only
+-- self:msg("set bundle links L1");
+
+ -- TODO
+-- local ip = c:getNode(pathl .. "ipaddr")
+-- if ip then
+-- string.match(ip:value(), "%d+%.%d+%.%d+%.%d+%/(%d+)")
+-- end
+
+ local def_local_addr = "0.0.0.0";
+ local def_perr_addr = "10.254.254.2";
+ if self.c:getNode(pathl .. "gateway"):value() then
+ def_perr_addr = self.c:getNode(pathl .. "gateway"):value();
+ end
+
+ self:msg("set iface addrs " .. def_local_addr .. " " .. def_perr_addr);
+ self:msg("set iface up-script /etc/mpd-linkup");
+ self:msg("set iface down-script /etc/mpd-linkdown");
+ self:msg("set ipcp ranges " .. def_local_addr .. "/0 " .. def_perr_addr .."/0");
+
+ -- We should apply default on a up-script run
+-- self:msg("set iface route default");
+
+ local dod = self.c:getNode(pathl .. "on-demand")
+ if dod and dod:attr("enable") == "true" then
+ self:msg("set iface enable on-demand");
+ self:msg("set iface idle " .. self.c:getNode(pathl .. "idle-time"):value());
+ end
+
+ self:msg("set iface name " .. bundle);
+
+ node = self.c:getNode(pathl .. "nat")
+ if node and node:attr("enable") == "true" then
+ self:msg("set iface enable nat");
+ end
+
+ self:msg("set ipcp enable req-pri-dns");
+ self:msg("set ipcp enable req-sec-dns");
+
+ self:msg("open iface");
+
+ self:msg("exit");
+ self.socket:close();
+
+ return (true);
+end
+
+function MPD:config_link(path, link, bundle)
+ local pathl = path .. ".";
+ self.socket = socket.connect(self.host, self.port);
+ if not self.socket then
+ print("Can't connect to " .. self.host .. ":" .. self.port);
+ return (nil);
+ end
+
+ local mpdtype = self.c:getNode(path);
+ if mpdtype and mpdtype:attr("type") then
+ mpdtype = mpdtype:attr("type");
+ else
+ return (nil);
+ end
+
+ self:msg("create link static " .. link .. " " .. mpdtype);
+ self:msg("link " .. link);
+
+ local user = self.c:getNode(pathl .. "username");
+ if user and user:value() and string.len(user:value()) > 0 then
+ self:msg("set auth authname " .. user:value());
+ local passwd = self.c:getNode(pathl .. "password");
+ if passwd and passwd:value() then
+ self:msg("set auth password \"" .. passwd:value() .. "\"");
+ else
+ self:msg("set auth password \"\"");
+ end
+ end
+
+ if mpdtype == "modem" then
+ self:msg("set modem device " ..
+ self.c:getNode(pathl .. "device"):value() .. "");
+ self:msg("set modem var $DialPrefix \"DT\"");
+ -- Try to send PPP request, for cases when modem stick at data mode
+ -- Leased Line.
+ self:msg("set modem var $TryPPPEarly \"yes\"");
+ self:msg("set modem var $Telephone \"" ..
+ self.c:getNode(pathl .. "phone"):value() .. "\"");
+ local initstring = self.c:getNode(pathl .. "init_string");
+ if initstring then -- If node
+ initstring = initstring:value();
+ if initstring and initstring ~= "" then -- If value not empty
+ -- Escape double quotes
+ initstring = initstring:gsub("\"", "\\\"");
+ print("set modem var $InitString \"" .. initstring .. "\"");
+ self:msg("set modem var $InitString \"" .. initstring .. "\"");
+ end
+ end
+ self:msg("set modem script DialPeer");
+ self:msg("set modem idle-script Ringback");
+ self:msg("set modem watch -cd");
+ elseif mpdtype == "pppoe" then
+ self:msg("set pppoe iface " .. self.c:getNode(pathl .. "device"):value() .. "");
+ local service_node = self.c:getNode(pathl .. "service_name");
+ if service_node and service_node:value() then
+ self:msg("set pppoe service \"" .. service_node:value() .. "\"");
+ end
+ elseif mpdtype == "pptp" then
+ -- TODO:
+ self:msg("set pptp self 10.1.3.3");
+ self:msg("set pptp peer 10.1.0.1");
+ self:msg("set pptp disable windowing");
+ end
+
+
+ -- TODO
+ self:msg("set link disable chap pap");
+ self:msg("set link accept chap pap");
+ self:msg("set link action bundle " .. bundle);
+ self:msg("set link enable incoming");
+ self:msg("set link max-redial 0");
+ self:msg("set link mtu 1460");
+ self:msg("set link keep-alive 10 60");
+-- self:msg("set link bandwidth 14194304");
+
+ -- Open link
+ self:msg("open");
+ self:msg("exit");
+ self.socket:close();
+
+
+
+ return (true);
+end
+
+function MPD:show_bundle(path, bundle)
+-- self.socket:refresh();
+ self.socket = socket.connect(self.host, self.port);
+
+ self:msg("bundle " .. bundle);
+ local info = self:msg("show bundle " .. bundle, 500);
+ self:msg("exit");
+ self.socket:close();
+
+ return (true);
+end
+
+function MPD:close()
+-- self.socket:close();
+end
+
+mt.__index = MPD;
+-----------------------------------
+-------- End of MPD Class --------
+-----------------------------------
+
+--[[
+Bundle 'PPP' (static):
+ Links : PPP[Opened/UP]
+ Status : OPEN
+ Session time : 1119 seconds
+ MultiSession Id: 249-PPP
+ Total bandwidth: 28800 bits/sec
+ Avail bandwidth: 28800 bits/sec
+ Peer authname : ""
+Configuration:
+ Retry timeout : 2 seconds
+ BW-manage:
+ Period : 60 seconds
+ Low mark : 20%
+ High mark : 80%
+ Min conn : 30 seconds
+ Min disc : 90 seconds
+ Links :
+Bundle level options:
+ ipcp enable
+ ipv6cp disable
+ compression disable
+ encryption disable
+ crypt-reqd disable
+ bw-manage disable
+ round-robin disable
+Multilink PPP:
+ Status : Inactive
+Traffic stats:
+ Input octets : 1322
+ Input frames : 19
+ Output octets : 1270
+ Output frames : 18
+ Bad protocols : 0
+ Runts : 0
+ Dup fragments : 0
+ Drop fragments : 0
+]]
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/node.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/node.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,68 @@
+-----------------------------------
+----------- Node Class ------------
+-----------------------------------
+Node = {};
+mtNode = {};
+
+function Node:new(s, path)
+
+ if type(s) ~= "table" then return (nil); end
+ local node = setmetatable({ node = s or '' }, mtNode);
+ node.path = path;
+ return (node);
+end
+
+function Node:dump(f, v)
+ if self.node then
+ if (not f) or f == "txt" then
+ if v then print("TEXT dump of \"" .. self.path .. "\"") end
+ return tdump(self.node);
+ elseif f == "xml" then
+ if v then print("XML dump of \"" .. self.path .. "\"") end
+ return xmldump(self.node);
+ else
+ print("Unknow format " .. f);
+ end
+ end
+end
+
+function Node:attr(attr, value)
+ if self.node._attr and type(self.node._attr) == "table" then
+ if value then
+ self.node._attr[attr] = value;
+ return (true);
+ else
+ return (self.node._attr[attr] or "");
+ end
+ end
+ return (nil);
+end
+
+function Node:value(_value)
+ if self.node._children and
+ self.node._children[1] and
+ self.node._children[1]._text then
+
+ if _value then
+ self.node._children[1]._text = _value;
+ return (true);
+ else
+ return (self.node._children[1]._text or "");
+ end
+
+ end
+
+ if _value then
+ if not self.node._children then
+ self.node._children = {};
+ end
+ table.insert(self.node._children, { _text = _value, _type = "TEXT" });
+ end
+
+ return (nil);
+end
+
+mtNode.__index = Node;
+-----------------------------------
+-------- End of Node Class --------
+-----------------------------------
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/pidfile.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/pidfile.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,69 @@
+
+function readpid(pidfilename)
+ local pidfile = io.open(pidfilename, "r");
+ if pidfile then
+ local pid = assert(pidfile:read("*n"));
+ pidfile:close();
+ return (pid);
+ end
+ -- TODO: rise error on read/open failures
+ return (nil);
+end
+
+
+--
+-- check(pidfilename)
+-- check for pid file and runnig process
+-- return ( 1) if process runnning
+-- return (-1) if stale pid file
+-- return ( 0) if no pid file
+--
+
+function checkpid(pidfilename)
+ local oldpid = readpid(pidfilename);
+ if oldpid and oldpid > 0 then
+ local ret = os.execute("ps -axo command= " .. oldpid);
+ if ret == 0 then
+ return (1); -- Process running
+ end
+ return (-1); -- Stale pid file, no process
+ end
+ return (0); -- No pid file found
+end
+
+--
+-- pidfile(pidfilename)
+-- check for runnig process and create new pid file otherwise
+-- if exit process if checked proccess running
+--
+
+function pidfile(pidfilename)
+ local psx = require("posix");
+ local pid = psx.getprocessid("pid");
+
+ if checkpid(pidfilename) == 1 then
+ print("pid file ".. pidfilename .. " locked")
+ os.exit(1);
+ end
+
+ pidfile = assert(io.open(pidfilename, "w"));
+ assert(pidfile:write(pid));
+ pidfile:close();
+
+ return (true);
+end
+
+
+function pidfile_signal(pidfilename, signal)
+ return (false);
+end
+
+--
+--
+-- Terminate running holder of pidfile, and write new pidfile
+--
+
+function pidfile_replace_stop()
+end
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/racoon.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/racoon.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,368 @@
+--[[
+
+file /etc/racoon/racoon.conf:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+path pidfile "/var/run/racoon.pid";
+path pre_shared_key "/var/db/racoon/racoon_psk.txt"; #location of pre-shared key file
+log notify; #log verbosity setting: set to 'notify' when testing and debugging is complete
+
+padding # options are not to be changed
+{
+ maximum_length 20;
+ randomize off;
+ strict_check off;
+ exclusive_tail off;
+}
+
+timer # timing options. change as needed
+{
+ counter 5;
+ interval 20 sec;
+ persend 1;
+# natt_keepalive 15 sec;
+ phase1 30 sec;
+ phase2 15 sec;
+}
+
+listen # address [port] that racoon will listening on
+{
+ isakmp 192.168.90.1 [500];
+ isakmp_natt 192.168.90.1 [4500];
+}
+
+include /var/run/racoon.links.conf
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+Generated /var/run/racoon.links.conf:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+include /var/run/racoon.10.0.0.2:500.conf
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+Generated /var/run/racoon.10.0.0.2:500.conf:
+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+
+remote 10.0.0.2 [500]
+{
+ exchange_mode main,aggressive;
+ doi ipsec_doi;
+ situation identity_only;
+ my_identifier address 10.0.0.1;
+ peers_identifier address 10.0.0.2;
+ lifetime time 28800 sec;
+ initial_contact on;
+ passive off;
+ proposal_check obey;
+ generate_policy off;
+
+ proposal {
+ encryption_algorithm 3des;
+ hash_algorithm md5;
+ authentication_method pre_shared_key;
+ dh_group 5;
+ }
+}
+sainfo (address 192.168.0.0/24 any address 192.168.2.0/24 any)
+{
+ pfs_group 5;
+ lifetime time 3600 sec;
+ encryption_algorithm 3des;
+ authentication_algorithm hmac_md5;
+ compression_algorithm deflate;
+}
+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+
+usage: racoon [-BdFv] [-a (port)] [-f (file)] [-l (file)] [-p (port)]
+ -B: install SA to the kernel from the file specified by the configuration file.
+ -d: debug level, more -d will generate more debug message.
+ -C: dump parsed config file.
+ -L: include location in debug messages
+ -F: run in foreground, do not become daemon.
+ -v: be more verbose
+ -a: port number for admin port.
+ -f: pathname for configuration file.
+ -l: pathname for log file.
+ -p: port number for isakmp (default: 500).
+ -P: port number for NAT-T (default: 4500).
+
+<ipsec>
+ <remote id="0" enable="true">
+ <gateway>10.0.0.2:500</gateway>
+ <exchange_mode>main,aggressive</exchange_mode>
+ <my_identifier>address 10.0.0.1</my_identifier>
+ <peers_identifier>address 10.0.0.2</peers_identifier>
+ <lifetime>time 28800 sec</lifetime>
+ <initial_contact>on</initial_contact>
+ <passive>off</passive>
+ <proposal_check>obey</proposal_check>
+ <nat_traversal>off</nat_traversal>
+ <generate_policy>off</generate_policy>
+ <proposal>
+ <encryption_algorithm>3des</encryption_algorithm>
+ <hash_algorithm>md5</hash_algorithm>
+ <authentication_method>pre_shared_key</authentication_method>
+ <dh_group>5</dh_group>
+ <psk>pskpskpsk</psk>
+ </proposal>
+ </remote>
+ <sainfo id="0" enable="true">
+ <src>address 192.168.0.0/24 any</src>
+ <dst>address 192.168.2.0/24 any</dst>
+ <pfs_group>5</pfs_group>
+ <lifetime>time 3600 sec</lifetime>
+ <encryption_algorithm>3des</encryption_algorithm>
+ <authentication_algorithm>hmac_md5</authentication_algorithm>
+ <compression_algorithm>deflate</compression_algorithm>
+ </sainfo>
+ <setkey>
+ <line>spdadd 192.168.0.0/24 192.168.2.0/24 any -P out ipsec esp/tunnel/10.0.0.1-10.0.0.2/use</line>
+ <line>spdadd 192.168.2.0/24 192.168.0.0/24 any -P in ipsec esp/tunnel/10.0.0.2-10.0.0.1/use</line>
+ <line></line>
+ <line></line>
+ </setkey>
+</ipsec>
+
+
+]]
+
+-- require("ipcalc");
+
+RACOON = {};
+local mt = {};
+
+
+function RACOON:new(c, debug)
+ t = {};
+ t.c = c;
+ t.remote_count = 0;
+ t.pidfile = "/var/run/racoon.pid";
+ t.logfile = "/var/log/racoon.log";
+ t.configfile = "/etc/racoon/racoon.conf";
+ t.linksfile = "/var/run/racoon.links.conf";
+ t.psk = "/var/db/racoon/racoon_psk.txt";
+
+ t.debug = debug;
+ return setmetatable(t, mt);
+end
+
+function RACOON:make_conf()
+
+ -- Generate linksfile
+ local f = assert(io.open(self.linksfile, "w"));
+ for i = 1,16,1 do
+ local ppath = "ipsec.remote[" ..i.. "]";
+ local node = self.c:getNode(ppath);
+ if node and node:attr("enable") == "true" then
+ local gw = self.c:getNode(ppath .. ".gateway"):value();
+ if gw then
+ f:write("include \"/var/run/racoon." .. gw .. ".conf\";\n");
+ t.remote_count = t.remote_count + 1;
+ else
+ print("Can't get " .. ppath .. ".gateway value");
+ return (nil);
+ end
+ end
+ end
+ if self.remote_count == 0 then
+ -- No remote targets, so nothing todo
+ print("No remote targets, so nothing todo");
+ return (nil);
+ end
+
+ for i = 1,16,1 do
+ local ppath = "ipsec.sainfo[" ..i.. "]";
+ local node = self.c:getNode(ppath);
+ if node and node:attr("enable") == "true" then
+ f:write("include \"/var/run/racoon.sainfo" .. i .. ".conf\";\n");
+ end
+ end
+ f:close();
+
+
+
+ local function addline(ppath, item, prep, confitem)
+ local ret = "";
+ local val = self.c:getNode(ppath .. "." .. (confitem or item)):value();
+ if val then
+ ret = (prep or "") .. item .. "\t" .. val .. ";\n";
+ else
+ print("Can't get " .. ppath .. "." .. (confitem or item) .." value");
+ end
+ return (ret);
+ end
+
+ -- XXX: We need setup routes per IPSec tunnel
+ local last_gw = nil;
+
+ for i = 1,16,1 do
+ local ppath = "ipsec.remote[" ..i.. "]";
+ local node = self.c:getNode(ppath);
+ if node and node:attr("enable") == "true" then
+ local gw = self.c:getNode(ppath .. ".gateway"):value();
+ local file = "/var/run/racoon." .. gw .. ".conf";
+ local remote = gw:gsub(":", " [") .. "]";
+ last_gw = gw:gsub(":.*", "");
+
+ local conf = "remote\t" .. remote .. "\n";
+
+ conf = conf .. "{\n";
+ conf = conf .. addline(ppath, "exchange_mode" , "\t");
+ conf = conf .. "\tdoi ipsec_doi;\n";
+ conf = conf .. "\tsituation identity_only;\n";
+ conf = conf .. "\tscript \"/etc/racoon/phase1-up.sh\" phase1_up;\n";
+ conf = conf .. "\tscript \"/etc/racoon/phase1-down.sh\" phase1_down;\n";
+
+ conf = conf .. addline(ppath, "my_identifier" , "\t");
+ conf = conf .. addline(ppath, "peers_identifier" , "\t");
+ conf = conf .. addline(ppath, "lifetime" , "\t");
+ conf = conf .. addline(ppath, "initial_contact" , "\t");
+ conf = conf .. addline(ppath, "passive" , "\t");
+ conf = conf .. addline(ppath, "proposal_check" , "\t");
+ conf = conf .. addline(ppath, "generate_policy" , "\t");
+ conf = conf .. "\tproposal {\n";
+ conf = conf .. addline(ppath, "encryption_algorithm", "\t\t", "proposal.encryption_algorithm");
+ conf = conf .. addline(ppath, "hash_algorithm" , "\t\t", "proposal.hash_algorithm");
+ conf = conf .. addline(ppath, "authentication_method","\t\t", "proposal.authentication_method");
+ conf = conf .. addline(ppath, "dh_group" , "\t\t", "proposal.dh_group");
+ conf = conf .. "\t}\n";
+ conf = conf .. "}\n";
+
+ print("IPsec Remote config file " .. file .. ":\n" ..
+ conf ..
+ "=======================================\n");
+
+ local f = assert(io.open(file, "w"));
+ f:write(conf);
+ f:close();
+
+ end
+ end
+
+ local route_up = nil;
+ local route_down = nil;
+
+ if last_gw then
+ local route_up_file = "/var/run/racoon." .. last_gw .. "_up.sh";
+ local route_down_file = "/var/run/racoon." .. last_gw .. "_down.sh";
+
+ route_up = assert(io.open(route_up_file, "w"));
+ route_down = assert(io.open(route_down_file, "w"));
+
+ route_up:write("#!/bin/sh\n");
+ route_down:write("#!/bin/sh\n");
+ end
+
+ for i = 1,16,1 do
+ local ppath = "ipsec.sainfo[" ..i.. "]";
+ local node = self.c:getNode(ppath);
+ if node and node:attr("enable") == "true" then
+ local file = "/var/run/racoon.sainfo" .. i .. ".conf";
+ local src = self.c:getNode(ppath .. ".src"):value();
+ local dst = self.c:getNode(ppath .. ".dst"):value();
+
+ dst_cidr = dst:gsub("^%S+%s+(%S+)%s+%S+", "%1");
+ if dst_cidr:match("%d+%.%d+%.%d+%.%d+%/%d+") then
+ -- Preinstall routes of secured remote nets
+ -- "already in table" ignored
+ local cmd = string.format(
+ "/sbin/route add %s -iface lo0 -reject", dst_cidr);
+ print(cmd);
+ os.execute(cmd);
+ if last_gw then
+ route_up:write(string.format("/sbin/route change %s %s\n", dst_cidr, last_gw));
+ route_down:write(string.format("/sbin/route change %s -iface lo0 -reject\n", dst_cidr));
+ end
+ end
+
+ local conf = "sainfo (" .. src .. " " .. dst .. ")\n";
+ conf = conf .. "{\n";
+ conf = conf .. addline(ppath, "pfs_group" , "\t");
+ conf = conf .. addline(ppath, "lifetime" , "\t");
+ conf = conf .. addline(ppath, "encryption_algorithm" , "\t");
+ conf = conf .. addline(ppath, "authentication_algorithm" , "\t");
+ conf = conf .. addline(ppath, "compression_algorithm" , "\t");
+ conf = conf .. "}\n";
+
+ print("IPsec SA info config file " .. file .. ":\n" ..
+ conf ..
+ "=======================================\n");
+
+ local f = assert(io.open(file, "w"));
+ f:write(conf);
+ f:close();
+ end
+ end
+ if last_gw then
+ route_up:close();
+ route_down:close();
+ end
+
+end
+
+function RACOON:make_psk()
+
+ -- Generate linksfile
+ local f = assert(io.open(self.psk, "w"));
+ for i = 1,16,1 do
+ local ppath = "ipsec.remote[" ..i.. "]";
+ local node = self.c:getNode(ppath);
+ if node and node:attr("enable") == "true" then
+ local gw = self.c:getNode(ppath .. ".gateway"):value();
+ if gw then
+ gw = gw:gsub(":.*", "");
+ local psk = self.c:getNode(ppath .. ".proposal.psk");
+ if psk then
+ f:write(gw .. "\t" .. psk:value() .. "\n");
+ end;
+ else
+ print("Can't get " .. ppath .. ".gateway value");
+ return (nil);
+ end
+ end
+ end
+ f:close();
+ os.execute("/bin/chmod 700 " .. self.psk);
+end
+
+function RACOON:setkey()
+ local setkey = "";
+
+ for i = 1,16,1 do
+ local ppath = "ipsec.setkey.line[" ..i.. "]";
+ local node = self.c:getNode(ppath);
+ if node then
+ local val = node:value();
+ if val and string.len(val) > 0 then
+ setkey = setkey .. val .. ";\n";
+ end
+ end
+ end
+
+ if string.len(setkey) > 0 then
+ local sk = io.popen("/sbin/setkey -c ", "w");
+ sk:write(setkey);
+ sk:close();
+ end
+end
+
+function RACOON:run()
+ -- FIXME install routes to remote nets via his IPSec gates
+ --os.execute("route add 192.168.2.0/24 10.0.0.1");
+ os.execute("mkdir -p /var/run/");
+ os.execute("mkdir -p /var/db/racoon");
+ self:setkey();
+ self:make_psk();
+ self:make_conf();
+ if self.remote_count > 0 then
+-- os.execute("echo 'WARNING: RACOON run in DEBUG mode' > /dev/console");
+-- os.execute("/sbin/racoon -ddddf " .. self.configfile .. " -l " .. self.logfile);
+ os.execute("/sbin/racoon -f " .. self.configfile .. " -l " .. self.logfile);
+ end
+end
+
+function RACOON:stop()
+
+ os.execute("kill `cat /var/run/racoon.pid`");
+end
+
+mt.__index = RACOON;
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,133 @@
+-----------------------------------------------------------------------------
+-- LuaSocket helper module
+-- Author: Diego Nehab
+-- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local string = require("string")
+local math = require("math")
+local socket = require("socket.core")
+module("socket")
+
+-----------------------------------------------------------------------------
+-- Exported auxiliar functions
+-----------------------------------------------------------------------------
+function connect(address, port, laddress, lport)
+ local sock, err = socket.tcp()
+ if not sock then return nil, err end
+ if laddress then
+ local res, err = sock:bind(laddress, lport, -1)
+ if not res then return nil, err end
+ end
+ local res, err = sock:connect(address, port)
+ if not res then return nil, err end
+ return sock
+end
+
+function bind(host, port, backlog)
+ local sock, err = socket.tcp()
+ if not sock then return nil, err end
+ sock:setoption("reuseaddr", true)
+ local res, err = sock:bind(host, port)
+ if not res then return nil, err end
+ res, err = sock:listen(backlog)
+ if not res then return nil, err end
+ return sock
+end
+
+try = newtry()
+
+function choose(table)
+ return function(name, opt1, opt2)
+ if base.type(name) ~= "string" then
+ name, opt1, opt2 = "default", name, opt1
+ end
+ local f = table[name or "nil"]
+ if not f then base.error("unknown key (".. base.tostring(name) ..")", 3)
+ else return f(opt1, opt2) end
+ end
+end
+
+-----------------------------------------------------------------------------
+-- Socket sources and sinks, conforming to LTN12
+-----------------------------------------------------------------------------
+-- create namespaces inside LuaSocket namespace
+sourcet = {}
+sinkt = {}
+
+BLOCKSIZE = 2048
+
+sinkt["close-when-done"] = function(sock)
+ return base.setmetatable({
+ getfd = function() return sock:getfd() end,
+ dirty = function() return sock:dirty() end
+ }, {
+ __call = function(self, chunk, err)
+ if not chunk then
+ sock:close()
+ return 1
+ else return sock:send(chunk) end
+ end
+ })
+end
+
+sinkt["keep-open"] = function(sock)
+ return base.setmetatable({
+ getfd = function() return sock:getfd() end,
+ dirty = function() return sock:dirty() end
+ }, {
+ __call = function(self, chunk, err)
+ if chunk then return sock:send(chunk)
+ else return 1 end
+ end
+ })
+end
+
+sinkt["default"] = sinkt["keep-open"]
+
+sink = choose(sinkt)
+
+sourcet["by-length"] = function(sock, length)
+ return base.setmetatable({
+ getfd = function() return sock:getfd() end,
+ dirty = function() return sock:dirty() end
+ }, {
+ __call = function()
+ if length <= 0 then return nil end
+ local size = math.min(socket.BLOCKSIZE, length)
+ local chunk, err = sock:receive(size)
+ if err then return nil, err end
+ length = length - string.len(chunk)
+ return chunk
+ end
+ })
+end
+
+sourcet["until-closed"] = function(sock)
+ local done
+ return base.setmetatable({
+ getfd = function() return sock:getfd() end,
+ dirty = function() return sock:dirty() end
+ }, {
+ __call = function()
+ if done then return nil end
+ local chunk, err, partial = sock:receive(socket.BLOCKSIZE)
+ if not err then return chunk
+ elseif err == "closed" then
+ sock:close()
+ done = 1
+ return partial
+ else return nil, err end
+ end
+ })
+end
+
+
+sourcet["default"] = sourcet["until-closed"]
+
+source = choose(sourcet)
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/ftp.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/ftp.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,281 @@
+-----------------------------------------------------------------------------
+-- FTP support for the Lua language
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local table = require("table")
+local string = require("string")
+local math = require("math")
+local socket = require("socket")
+local url = require("socket.url")
+local tp = require("socket.tp")
+local ltn12 = require("ltn12")
+module("socket.ftp")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+-- timeout in seconds before the program gives up on a connection
+TIMEOUT = 60
+-- default port for ftp service
+PORT = 21
+-- this is the default anonymous password. used when no password is
+-- provided in url. should be changed to your e-mail.
+USER = "ftp"
+PASSWORD = "anonymous at anonymous.org"
+
+-----------------------------------------------------------------------------
+-- Low level FTP API
+-----------------------------------------------------------------------------
+local metat = { __index = {} }
+
+function open(server, port, create)
+ local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create))
+ local f = base.setmetatable({ tp = tp }, metat)
+ -- make sure everything gets closed in an exception
+ f.try = socket.newtry(function() f:close() end)
+ return f
+end
+
+function metat.__index:portconnect()
+ self.try(self.server:settimeout(TIMEOUT))
+ self.data = self.try(self.server:accept())
+ self.try(self.data:settimeout(TIMEOUT))
+end
+
+function metat.__index:pasvconnect()
+ self.data = self.try(socket.tcp())
+ self.try(self.data:settimeout(TIMEOUT))
+ self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
+end
+
+function metat.__index:login(user, password)
+ self.try(self.tp:command("user", user or USER))
+ local code, reply = self.try(self.tp:check{"2..", 331})
+ if code == 331 then
+ self.try(self.tp:command("pass", password or PASSWORD))
+ self.try(self.tp:check("2.."))
+ end
+ return 1
+end
+
+function metat.__index:pasv()
+ self.try(self.tp:command("pasv"))
+ local code, reply = self.try(self.tp:check("2.."))
+ local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
+ local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
+ self.try(a and b and c and d and p1 and p2, reply)
+ self.pasvt = {
+ ip = string.format("%d.%d.%d.%d", a, b, c, d),
+ port = p1*256 + p2
+ }
+ if self.server then
+ self.server:close()
+ self.server = nil
+ end
+ return self.pasvt.ip, self.pasvt.port
+end
+
+function metat.__index:port(ip, port)
+ self.pasvt = nil
+ if not ip then
+ ip, port = self.try(self.tp:getcontrol():getsockname())
+ self.server = self.try(socket.bind(ip, 0))
+ ip, port = self.try(self.server:getsockname())
+ self.try(self.server:settimeout(TIMEOUT))
+ end
+ local pl = math.mod(port, 256)
+ local ph = (port - pl)/256
+ local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
+ self.try(self.tp:command("port", arg))
+ self.try(self.tp:check("2.."))
+ return 1
+end
+
+function metat.__index:send(sendt)
+ self.try(self.pasvt or self.server, "need port or pasv first")
+ -- if there is a pasvt table, we already sent a PASV command
+ -- we just get the data connection into self.data
+ if self.pasvt then self:pasvconnect() end
+ -- get the transfer argument and command
+ local argument = sendt.argument or
+ url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
+ if argument == "" then argument = nil end
+ local command = sendt.command or "stor"
+ -- send the transfer command and check the reply
+ self.try(self.tp:command(command, argument))
+ local code, reply = self.try(self.tp:check{"2..", "1.."})
+ -- if there is not a a pasvt table, then there is a server
+ -- and we already sent a PORT command
+ if not self.pasvt then self:portconnect() end
+ -- get the sink, source and step for the transfer
+ local step = sendt.step or ltn12.pump.step
+ local readt = {self.tp.c}
+ local checkstep = function(src, snk)
+ -- check status in control connection while downloading
+ local readyt = socket.select(readt, nil, 0)
+ if readyt[tp] then code = self.try(self.tp:check("2..")) end
+ return step(src, snk)
+ end
+ local sink = socket.sink("close-when-done", self.data)
+ -- transfer all data and check error
+ self.try(ltn12.pump.all(sendt.source, sink, checkstep))
+ if string.find(code, "1..") then self.try(self.tp:check("2..")) end
+ -- done with data connection
+ self.data:close()
+ -- find out how many bytes were sent
+ local sent = socket.skip(1, self.data:getstats())
+ self.data = nil
+ return sent
+end
+
+function metat.__index:receive(recvt)
+ self.try(self.pasvt or self.server, "need port or pasv first")
+ if self.pasvt then self:pasvconnect() end
+ local argument = recvt.argument or
+ url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
+ if argument == "" then argument = nil end
+ local command = recvt.command or "retr"
+ self.try(self.tp:command(command, argument))
+ local code = self.try(self.tp:check{"1..", "2.."})
+ if not self.pasvt then self:portconnect() end
+ local source = socket.source("until-closed", self.data)
+ local step = recvt.step or ltn12.pump.step
+ self.try(ltn12.pump.all(source, recvt.sink, step))
+ if string.find(code, "1..") then self.try(self.tp:check("2..")) end
+ self.data:close()
+ self.data = nil
+ return 1
+end
+
+function metat.__index:cwd(dir)
+ self.try(self.tp:command("cwd", dir))
+ self.try(self.tp:check(250))
+ return 1
+end
+
+function metat.__index:type(type)
+ self.try(self.tp:command("type", type))
+ self.try(self.tp:check(200))
+ return 1
+end
+
+function metat.__index:greet()
+ local code = self.try(self.tp:check{"1..", "2.."})
+ if string.find(code, "1..") then self.try(self.tp:check("2..")) end
+ return 1
+end
+
+function metat.__index:quit()
+ self.try(self.tp:command("quit"))
+ self.try(self.tp:check("2.."))
+ return 1
+end
+
+function metat.__index:close()
+ if self.data then self.data:close() end
+ if self.server then self.server:close() end
+ return self.tp:close()
+end
+
+-----------------------------------------------------------------------------
+-- High level FTP API
+-----------------------------------------------------------------------------
+local function override(t)
+ if t.url then
+ local u = url.parse(t.url)
+ for i,v in base.pairs(t) do
+ u[i] = v
+ end
+ return u
+ else return t end
+end
+
+local function tput(putt)
+ putt = override(putt)
+ socket.try(putt.host, "missing hostname")
+ local f = open(putt.host, putt.port, putt.create)
+ f:greet()
+ f:login(putt.user, putt.password)
+ if putt.type then f:type(putt.type) end
+ f:pasv()
+ local sent = f:send(putt)
+ f:quit()
+ f:close()
+ return sent
+end
+
+local default = {
+ path = "/",
+ scheme = "ftp"
+}
+
+local function parse(u)
+ local t = socket.try(url.parse(u, default))
+ socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
+ socket.try(t.host, "missing hostname")
+ local pat = "^type=(.)$"
+ if t.params then
+ t.type = socket.skip(2, string.find(t.params, pat))
+ socket.try(t.type == "a" or t.type == "i",
+ "invalid type '" .. t.type .. "'")
+ end
+ return t
+end
+
+local function sput(u, body)
+ local putt = parse(u)
+ putt.source = ltn12.source.string(body)
+ return tput(putt)
+end
+
+put = socket.protect(function(putt, body)
+ if base.type(putt) == "string" then return sput(putt, body)
+ else return tput(putt) end
+end)
+
+local function tget(gett)
+ gett = override(gett)
+ socket.try(gett.host, "missing hostname")
+ local f = open(gett.host, gett.port, gett.create)
+ f:greet()
+ f:login(gett.user, gett.password)
+ if gett.type then f:type(gett.type) end
+ f:pasv()
+ f:receive(gett)
+ f:quit()
+ return f:close()
+end
+
+local function sget(u)
+ local gett = parse(u)
+ local t = {}
+ gett.sink = ltn12.sink.table(t)
+ tget(gett)
+ return table.concat(t)
+end
+
+command = socket.protect(function(cmdt)
+ cmdt = override(cmdt)
+ socket.try(cmdt.host, "missing hostname")
+ socket.try(cmdt.command, "missing command")
+ local f = open(cmdt.host, cmdt.port, cmdt.create)
+ f:greet()
+ f:login(cmdt.user, cmdt.password)
+ f.try(f.tp:command(cmdt.command, cmdt.argument))
+ if cmdt.check then f.try(f.tp:check(cmdt.check)) end
+ f:quit()
+ return f:close()
+end)
+
+get = socket.protect(function(gett)
+ if base.type(gett) == "string" then return sget(gett)
+ else return tget(gett) end
+end)
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/http.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/http.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,350 @@
+-----------------------------------------------------------------------------
+-- HTTP/1.1 client support for the Lua language.
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: http.lua,v 1.71 2007/10/13 23:55:20 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-------------------------------------------------------------------------------
+local socket = require("socket")
+local url = require("socket.url")
+local ltn12 = require("ltn12")
+local mime = require("mime")
+local string = require("string")
+local base = _G
+local table = require("table")
+module("socket.http")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+-- connection timeout in seconds
+TIMEOUT = 60
+-- default port for document retrieval
+PORT = 80
+-- user agent field sent in request
+USERAGENT = socket._VERSION
+
+-----------------------------------------------------------------------------
+-- Reads MIME headers from a connection, unfolding where needed
+-----------------------------------------------------------------------------
+local function receiveheaders(sock, headers)
+ local line, name, value, err
+ headers = headers or {}
+ -- get first line
+ line, err = sock:receive()
+ if err then return nil, err end
+ -- headers go until a blank line is found
+ while line ~= "" do
+ -- get field-name and value
+ name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
+ if not (name and value) then return nil, "malformed reponse headers" end
+ name = string.lower(name)
+ -- get next line (value might be folded)
+ line, err = sock:receive()
+ if err then return nil, err end
+ -- unfold any folded values
+ while string.find(line, "^%s") do
+ value = value .. line
+ line = sock:receive()
+ if err then return nil, err end
+ end
+ -- save pair in table
+ if headers[name] then headers[name] = headers[name] .. ", " .. value
+ else headers[name] = value end
+ end
+ return headers
+end
+
+-----------------------------------------------------------------------------
+-- Extra sources and sinks
+-----------------------------------------------------------------------------
+socket.sourcet["http-chunked"] = function(sock, headers)
+ return base.setmetatable({
+ getfd = function() return sock:getfd() end,
+ dirty = function() return sock:dirty() end
+ }, {
+ __call = function()
+ -- get chunk size, skip extention
+ local line, err = sock:receive()
+ if err then return nil, err end
+ local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
+ if not size then return nil, "invalid chunk size" end
+ -- was it the last chunk?
+ if size > 0 then
+ -- if not, get chunk and skip terminating CRLF
+ local chunk, err, part = sock:receive(size)
+ if chunk then sock:receive() end
+ return chunk, err
+ else
+ -- if it was, read trailers into headers table
+ headers, err = receiveheaders(sock, headers)
+ if not headers then return nil, err end
+ end
+ end
+ })
+end
+
+socket.sinkt["http-chunked"] = function(sock)
+ return base.setmetatable({
+ getfd = function() return sock:getfd() end,
+ dirty = function() return sock:dirty() end
+ }, {
+ __call = function(self, chunk, err)
+ if not chunk then return sock:send("0\r\n\r\n") end
+ local size = string.format("%X\r\n", string.len(chunk))
+ return sock:send(size .. chunk .. "\r\n")
+ end
+ })
+end
+
+-----------------------------------------------------------------------------
+-- Low level HTTP API
+-----------------------------------------------------------------------------
+local metat = { __index = {} }
+
+function open(host, port, create)
+ -- create socket with user connect function, or with default
+ local c = socket.try((create or socket.tcp)())
+ local h = base.setmetatable({ c = c }, metat)
+ -- create finalized try
+ h.try = socket.newtry(function() h:close() end)
+ -- set timeout before connecting
+ h.try(c:settimeout(TIMEOUT))
+ h.try(c:connect(host, port or PORT))
+ -- here everything worked
+ return h
+end
+
+function metat.__index:sendrequestline(method, uri)
+ local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
+ return self.try(self.c:send(reqline))
+end
+
+function metat.__index:sendheaders(headers)
+ local h = "\r\n"
+ for i, v in base.pairs(headers) do
+ h = i .. ": " .. v .. "\r\n" .. h
+ end
+ self.try(self.c:send(h))
+ return 1
+end
+
+function metat.__index:sendbody(headers, source, step)
+ source = source or ltn12.source.empty()
+ step = step or ltn12.pump.step
+ -- if we don't know the size in advance, send chunked and hope for the best
+ local mode = "http-chunked"
+ if headers["content-length"] then mode = "keep-open" end
+ return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
+end
+
+function metat.__index:receivestatusline()
+ local status = self.try(self.c:receive(5))
+ -- identify HTTP/0.9 responses, which do not contain a status line
+ -- this is just a heuristic, but is what the RFC recommends
+ if status ~= "HTTP/" then return nil, status end
+ -- otherwise proceed reading a status line
+ status = self.try(self.c:receive("*l", status))
+ local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
+ return self.try(base.tonumber(code), status)
+end
+
+function metat.__index:receiveheaders()
+ return self.try(receiveheaders(self.c))
+end
+
+function metat.__index:receivebody(headers, sink, step)
+ sink = sink or ltn12.sink.null()
+ step = step or ltn12.pump.step
+ local length = base.tonumber(headers["content-length"])
+ local t = headers["transfer-encoding"] -- shortcut
+ local mode = "default" -- connection close
+ if t and t ~= "identity" then mode = "http-chunked"
+ elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
+ return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
+ sink, step))
+end
+
+function metat.__index:receive09body(status, sink, step)
+ local source = ltn12.source.rewind(socket.source("until-closed", self.c))
+ source(status)
+ return self.try(ltn12.pump.all(source, sink, step))
+end
+
+function metat.__index:close()
+ return self.c:close()
+end
+
+-----------------------------------------------------------------------------
+-- High level HTTP API
+-----------------------------------------------------------------------------
+local function adjusturi(reqt)
+ local u = reqt
+ -- if there is a proxy, we need the full url. otherwise, just a part.
+ if not reqt.proxy and not PROXY then
+ u = {
+ path = socket.try(reqt.path, "invalid path 'nil'"),
+ params = reqt.params,
+ query = reqt.query,
+ fragment = reqt.fragment
+ }
+ end
+ return url.build(u)
+end
+
+local function adjustproxy(reqt)
+ local proxy = reqt.proxy or PROXY
+ if proxy then
+ proxy = url.parse(proxy)
+ return proxy.host, proxy.port or 3128
+ else
+ return reqt.host, reqt.port
+ end
+end
+
+local function adjustheaders(reqt)
+ -- default headers
+ local lower = {
+ ["user-agent"] = USERAGENT,
+ ["host"] = reqt.host,
+ ["connection"] = "close, TE",
+ ["te"] = "trailers"
+ }
+ -- if we have authentication information, pass it along
+ if reqt.user and reqt.password then
+ lower["authorization"] =
+ "Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
+ end
+ -- override with user headers
+ for i,v in base.pairs(reqt.headers or lower) do
+ lower[string.lower(i)] = v
+ end
+ return lower
+end
+
+-- default url parts
+local default = {
+ host = "",
+ port = PORT,
+ path ="/",
+ scheme = "http"
+}
+
+local function adjustrequest(reqt)
+ -- parse url if provided
+ local nreqt = reqt.url and url.parse(reqt.url, default) or {}
+ -- explicit components override url
+ for i,v in base.pairs(reqt) do nreqt[i] = v end
+ if nreqt.port == "" then nreqt.port = 80 end
+ socket.try(nreqt.host and nreqt.host ~= "",
+ "invalid host '" .. base.tostring(nreqt.host) .. "'")
+ -- compute uri if user hasn't overriden
+ nreqt.uri = reqt.uri or adjusturi(nreqt)
+ -- ajust host and port if there is a proxy
+ nreqt.host, nreqt.port = adjustproxy(nreqt)
+ -- adjust headers in request
+ nreqt.headers = adjustheaders(nreqt)
+ return nreqt
+end
+
+local function shouldredirect(reqt, code, headers)
+ return headers.location and
+ string.gsub(headers.location, "%s", "") ~= "" and
+ (reqt.redirect ~= false) and
+ (code == 301 or code == 302) and
+ (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
+ and (not reqt.nredirects or reqt.nredirects < 5)
+end
+
+local function shouldreceivebody(reqt, code)
+ if reqt.method == "HEAD" then return nil end
+ if code == 204 or code == 304 then return nil end
+ if code >= 100 and code < 200 then return nil end
+ return 1
+end
+
+-- forward declarations
+local trequest, tredirect
+
+function tredirect(reqt, location)
+ local result, code, headers, status = trequest {
+ -- the RFC says the redirect URL has to be absolute, but some
+ -- servers do not respect that
+ url = url.absolute(reqt.url, location),
+ source = reqt.source,
+ sink = reqt.sink,
+ headers = reqt.headers,
+ proxy = reqt.proxy,
+ nredirects = (reqt.nredirects or 0) + 1,
+ create = reqt.create
+ }
+ -- pass location header back as a hint we redirected
+ headers = headers or {}
+ headers.location = headers.location or location
+ return result, code, headers, status
+end
+
+function trequest(reqt)
+ -- we loop until we get what we want, or
+ -- until we are sure there is no way to get it
+ local nreqt = adjustrequest(reqt)
+ local h = open(nreqt.host, nreqt.port, nreqt.create)
+ -- send request line and headers
+ h:sendrequestline(nreqt.method, nreqt.uri)
+ h:sendheaders(nreqt.headers)
+ -- if there is a body, send it
+ if nreqt.source then
+ h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
+ end
+ local code, status = h:receivestatusline()
+ -- if it is an HTTP/0.9 server, simply get the body and we are done
+ if not code then
+ h:receive09body(status, nreqt.sink, nreqt.step)
+ return 1, 200
+ end
+ local headers
+ -- ignore any 100-continue messages
+ while code == 100 do
+ headers = h:receiveheaders()
+ code, status = h:receivestatusline()
+ end
+ headers = h:receiveheaders()
+ -- at this point we should have a honest reply from the server
+ -- we can't redirect if we already used the source, so we report the error
+ if shouldredirect(nreqt, code, headers) and not nreqt.source then
+ h:close()
+ return tredirect(reqt, headers.location)
+ end
+ -- here we are finally done
+ if shouldreceivebody(nreqt, code) then
+ h:receivebody(headers, nreqt.sink, nreqt.step)
+ end
+ h:close()
+ return 1, code, headers, status
+end
+
+local function srequest(u, b)
+ local t = {}
+ local reqt = {
+ url = u,
+ sink = ltn12.sink.table(t)
+ }
+ if b then
+ reqt.source = ltn12.source.string(b)
+ reqt.headers = {
+ ["content-length"] = string.len(b),
+ ["content-type"] = "application/x-www-form-urlencoded"
+ }
+ reqt.method = "POST"
+ end
+ local code, headers, status = socket.skip(1, trequest(reqt))
+ return table.concat(t), code, headers, status
+end
+
+request = socket.protect(function(reqt, body)
+ if base.type(reqt) == "string" then return srequest(reqt, body)
+ else return trequest(reqt) end
+end)
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/smtp.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/smtp.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,251 @@
+-----------------------------------------------------------------------------
+-- SMTP client support for the Lua language.
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: smtp.lua,v 1.46 2007/03/12 04:08:40 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local coroutine = require("coroutine")
+local string = require("string")
+local math = require("math")
+local os = require("os")
+local socket = require("socket")
+local tp = require("socket.tp")
+local ltn12 = require("ltn12")
+local mime = require("mime")
+module("socket.smtp")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+-- timeout for connection
+TIMEOUT = 60
+-- default server used to send e-mails
+SERVER = "localhost"
+-- default port
+PORT = 25
+-- domain used in HELO command and default sendmail
+-- If we are under a CGI, try to get from environment
+DOMAIN = os.getenv("SERVER_NAME") or "localhost"
+-- default time zone (means we don't know)
+ZONE = "-0000"
+
+---------------------------------------------------------------------------
+-- Low level SMTP API
+-----------------------------------------------------------------------------
+local metat = { __index = {} }
+
+function metat.__index:greet(domain)
+ self.try(self.tp:check("2.."))
+ self.try(self.tp:command("EHLO", domain or DOMAIN))
+ return socket.skip(1, self.try(self.tp:check("2..")))
+end
+
+function metat.__index:mail(from)
+ self.try(self.tp:command("MAIL", "FROM:" .. from))
+ return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:rcpt(to)
+ self.try(self.tp:command("RCPT", "TO:" .. to))
+ return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:data(src, step)
+ self.try(self.tp:command("DATA"))
+ self.try(self.tp:check("3.."))
+ self.try(self.tp:source(src, step))
+ self.try(self.tp:send("\r\n.\r\n"))
+ return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:quit()
+ self.try(self.tp:command("QUIT"))
+ return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:close()
+ return self.tp:close()
+end
+
+function metat.__index:login(user, password)
+ self.try(self.tp:command("AUTH", "LOGIN"))
+ self.try(self.tp:check("3.."))
+ self.try(self.tp:command(mime.b64(user)))
+ self.try(self.tp:check("3.."))
+ self.try(self.tp:command(mime.b64(password)))
+ return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:plain(user, password)
+ local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
+ self.try(self.tp:command("AUTH", auth))
+ return self.try(self.tp:check("2.."))
+end
+
+function metat.__index:auth(user, password, ext)
+ if not user or not password then return 1 end
+ if string.find(ext, "AUTH[^\n]+LOGIN") then
+ return self:login(user, password)
+ elseif string.find(ext, "AUTH[^\n]+PLAIN") then
+ return self:plain(user, password)
+ else
+ self.try(nil, "authentication not supported")
+ end
+end
+
+-- send message or throw an exception
+function metat.__index:send(mailt)
+ self:mail(mailt.from)
+ if base.type(mailt.rcpt) == "table" then
+ for i,v in base.ipairs(mailt.rcpt) do
+ self:rcpt(v)
+ end
+ else
+ self:rcpt(mailt.rcpt)
+ end
+ self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
+end
+
+function open(server, port, create)
+ local tp = socket.try(tp.connect(server or SERVER, port or PORT,
+ TIMEOUT, create))
+ local s = base.setmetatable({tp = tp}, metat)
+ -- make sure tp is closed if we get an exception
+ s.try = socket.newtry(function()
+ s:close()
+ end)
+ return s
+end
+
+-- convert headers to lowercase
+local function lower_headers(headers)
+ local lower = {}
+ for i,v in base.pairs(headers or lower) do
+ lower[string.lower(i)] = v
+ end
+ return lower
+end
+
+---------------------------------------------------------------------------
+-- Multipart message source
+-----------------------------------------------------------------------------
+-- returns a hopefully unique mime boundary
+local seqno = 0
+local function newboundary()
+ seqno = seqno + 1
+ return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
+ math.random(0, 99999), seqno)
+end
+
+-- send_message forward declaration
+local send_message
+
+-- yield the headers all at once, it's faster
+local function send_headers(headers)
+ local h = "\r\n"
+ for i,v in base.pairs(headers) do
+ h = i .. ': ' .. v .. "\r\n" .. h
+ end
+ coroutine.yield(h)
+end
+
+-- yield multipart message body from a multipart message table
+local function send_multipart(mesgt)
+ -- make sure we have our boundary and send headers
+ local bd = newboundary()
+ local headers = lower_headers(mesgt.headers or {})
+ headers['content-type'] = headers['content-type'] or 'multipart/mixed'
+ headers['content-type'] = headers['content-type'] ..
+ '; boundary="' .. bd .. '"'
+ send_headers(headers)
+ -- send preamble
+ if mesgt.body.preamble then
+ coroutine.yield(mesgt.body.preamble)
+ coroutine.yield("\r\n")
+ end
+ -- send each part separated by a boundary
+ for i, m in base.ipairs(mesgt.body) do
+ coroutine.yield("\r\n--" .. bd .. "\r\n")
+ send_message(m)
+ end
+ -- send last boundary
+ coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
+ -- send epilogue
+ if mesgt.body.epilogue then
+ coroutine.yield(mesgt.body.epilogue)
+ coroutine.yield("\r\n")
+ end
+end
+
+-- yield message body from a source
+local function send_source(mesgt)
+ -- make sure we have a content-type
+ local headers = lower_headers(mesgt.headers or {})
+ headers['content-type'] = headers['content-type'] or
+ 'text/plain; charset="iso-8859-1"'
+ send_headers(headers)
+ -- send body from source
+ while true do
+ local chunk, err = mesgt.body()
+ if err then coroutine.yield(nil, err)
+ elseif chunk then coroutine.yield(chunk)
+ else break end
+ end
+end
+
+-- yield message body from a string
+local function send_string(mesgt)
+ -- make sure we have a content-type
+ local headers = lower_headers(mesgt.headers or {})
+ headers['content-type'] = headers['content-type'] or
+ 'text/plain; charset="iso-8859-1"'
+ send_headers(headers)
+ -- send body from string
+ coroutine.yield(mesgt.body)
+end
+
+-- message source
+function send_message(mesgt)
+ if base.type(mesgt.body) == "table" then send_multipart(mesgt)
+ elseif base.type(mesgt.body) == "function" then send_source(mesgt)
+ else send_string(mesgt) end
+end
+
+-- set defaul headers
+local function adjust_headers(mesgt)
+ local lower = lower_headers(mesgt.headers)
+ lower["date"] = lower["date"] or
+ os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
+ lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
+ -- this can't be overriden
+ lower["mime-version"] = "1.0"
+ return lower
+end
+
+function message(mesgt)
+ mesgt.headers = adjust_headers(mesgt)
+ -- create and return message source
+ local co = coroutine.create(function() send_message(mesgt) end)
+ return function()
+ local ret, a, b = coroutine.resume(co)
+ if ret then return a, b
+ else return nil, a end
+ end
+end
+
+---------------------------------------------------------------------------
+-- High level SMTP API
+-----------------------------------------------------------------------------
+send = socket.protect(function(mailt)
+ local s = open(mailt.server, mailt.port, mailt.create)
+ local ext = s:greet(mailt.domain)
+ s:auth(mailt.user, mailt.password, ext)
+ s:send(mailt)
+ s:quit()
+ return s:close()
+end)
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/tp.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/tp.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,123 @@
+-----------------------------------------------------------------------------
+-- Unified SMTP/FTP subsystem
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module and import dependencies
+-----------------------------------------------------------------------------
+local base = _G
+local string = require("string")
+local socket = require("socket")
+local ltn12 = require("ltn12")
+module("socket.tp")
+
+-----------------------------------------------------------------------------
+-- Program constants
+-----------------------------------------------------------------------------
+TIMEOUT = 60
+
+-----------------------------------------------------------------------------
+-- Implementation
+-----------------------------------------------------------------------------
+-- gets server reply (works for SMTP and FTP)
+local function get_reply(c)
+ local code, current, sep
+ local line, err = c:receive()
+ local reply = line
+ if err then return nil, err end
+ code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
+ if not code then return nil, "invalid server reply" end
+ if sep == "-" then -- reply is multiline
+ repeat
+ line, err = c:receive()
+ if err then return nil, err end
+ current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
+ reply = reply .. "\n" .. line
+ -- reply ends with same code
+ until code == current and sep == " "
+ end
+ return code, reply
+end
+
+-- metatable for sock object
+local metat = { __index = {} }
+
+function metat.__index:check(ok)
+ local code, reply = get_reply(self.c)
+ if not code then return nil, reply end
+ if base.type(ok) ~= "function" then
+ if base.type(ok) == "table" then
+ for i, v in base.ipairs(ok) do
+ if string.find(code, v) then
+ return base.tonumber(code), reply
+ end
+ end
+ return nil, reply
+ else
+ if string.find(code, ok) then return base.tonumber(code), reply
+ else return nil, reply end
+ end
+ else return ok(base.tonumber(code), reply) end
+end
+
+function metat.__index:command(cmd, arg)
+ if arg then
+ return self.c:send(cmd .. " " .. arg.. "\r\n")
+ else
+ return self.c:send(cmd .. "\r\n")
+ end
+end
+
+function metat.__index:sink(snk, pat)
+ local chunk, err = c:receive(pat)
+ return snk(chunk, err)
+end
+
+function metat.__index:send(data)
+ return self.c:send(data)
+end
+
+function metat.__index:receive(pat)
+ return self.c:receive(pat)
+end
+
+function metat.__index:getfd()
+ return self.c:getfd()
+end
+
+function metat.__index:dirty()
+ return self.c:dirty()
+end
+
+function metat.__index:getcontrol()
+ return self.c
+end
+
+function metat.__index:source(source, step)
+ local sink = socket.sink("keep-open", self.c)
+ local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
+ return ret, err
+end
+
+-- closes the underlying c
+function metat.__index:close()
+ self.c:close()
+ return 1
+end
+
+-- connect with server and return c object
+function connect(host, port, timeout, create)
+ local c, e = (create or socket.tcp)()
+ if not c then return nil, e end
+ c:settimeout(timeout or TIMEOUT)
+ local r, e = c:connect(host, port)
+ if not r then
+ c:close()
+ return nil, e
+ end
+ return base.setmetatable({c = c}, metat)
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/socket/url.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/socket/url.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,297 @@
+-----------------------------------------------------------------------------
+-- URI parsing, composition and relative URL resolution
+-- LuaSocket toolkit.
+-- Author: Diego Nehab
+-- RCS ID: $Id: url.lua,v 1.38 2006/04/03 04:45:42 diego Exp $
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+-- Declare module
+-----------------------------------------------------------------------------
+local string = require("string")
+local base = _G
+local table = require("table")
+module("socket.url")
+
+-----------------------------------------------------------------------------
+-- Module version
+-----------------------------------------------------------------------------
+_VERSION = "URL 1.0.1"
+
+-----------------------------------------------------------------------------
+-- Encodes a string into its escaped hexadecimal representation
+-- Input
+-- s: binary string to be encoded
+-- Returns
+-- escaped representation of string binary
+-----------------------------------------------------------------------------
+function escape(s)
+ return string.gsub(s, "([^A-Za-z0-9_])", function(c)
+ return string.format("%%%02x", string.byte(c))
+ end)
+end
+
+-----------------------------------------------------------------------------
+-- Protects a path segment, to prevent it from interfering with the
+-- url parsing.
+-- Input
+-- s: binary string to be encoded
+-- Returns
+-- escaped representation of string binary
+-----------------------------------------------------------------------------
+local function make_set(t)
+ local s = {}
+ for i,v in base.ipairs(t) do
+ s[t[i]] = 1
+ end
+ return s
+end
+
+-- these are allowed withing a path segment, along with alphanum
+-- other characters must be escaped
+local segment_set = make_set {
+ "-", "_", ".", "!", "~", "*", "'", "(",
+ ")", ":", "@", "&", "=", "+", "$", ",",
+}
+
+local function protect_segment(s)
+ return string.gsub(s, "([^A-Za-z0-9_])", function (c)
+ if segment_set[c] then return c
+ else return string.format("%%%02x", string.byte(c)) end
+ end)
+end
+
+-----------------------------------------------------------------------------
+-- Encodes a string into its escaped hexadecimal representation
+-- Input
+-- s: binary string to be encoded
+-- Returns
+-- escaped representation of string binary
+-----------------------------------------------------------------------------
+function unescape(s)
+ return string.gsub(s, "%%(%x%x)", function(hex)
+ return string.char(base.tonumber(hex, 16))
+ end)
+end
+
+-----------------------------------------------------------------------------
+-- Builds a path from a base path and a relative path
+-- Input
+-- base_path
+-- relative_path
+-- Returns
+-- corresponding absolute path
+-----------------------------------------------------------------------------
+local function absolute_path(base_path, relative_path)
+ if string.sub(relative_path, 1, 1) == "/" then return relative_path end
+ local path = string.gsub(base_path, "[^/]*$", "")
+ path = path .. relative_path
+ path = string.gsub(path, "([^/]*%./)", function (s)
+ if s ~= "./" then return s else return "" end
+ end)
+ path = string.gsub(path, "/%.$", "/")
+ local reduced
+ while reduced ~= path do
+ reduced = path
+ path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
+ if s ~= "../../" then return "" else return s end
+ end)
+ end
+ path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
+ if s ~= "../.." then return "" else return s end
+ end)
+ return path
+end
+
+-----------------------------------------------------------------------------
+-- Parses a url and returns a table with all its parts according to RFC 2396
+-- The following grammar describes the names given to the URL parts
+-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
+-- <authority> ::= <userinfo>@<host>:<port>
+-- <userinfo> ::= <user>[:<password>]
+-- <path> :: = {<segment>/}<segment>
+-- Input
+-- url: uniform resource locator of request
+-- default: table with default values for each field
+-- Returns
+-- table with the following fields, where RFC naming conventions have
+-- been preserved:
+-- scheme, authority, userinfo, user, password, host, port,
+-- path, params, query, fragment
+-- Obs:
+-- the leading '/' in {/<path>} is considered part of <path>
+-----------------------------------------------------------------------------
+function parse(url, default)
+ -- initialize default parameters
+ local parsed = {}
+ for i,v in base.pairs(default or parsed) do parsed[i] = v end
+ -- empty url is parsed to nil
+ if not url or url == "" then return nil, "invalid url" end
+ -- remove whitespace
+ -- url = string.gsub(url, "%s", "")
+ -- get fragment
+ url = string.gsub(url, "#(.*)$", function(f)
+ parsed.fragment = f
+ return ""
+ end)
+ -- get scheme
+ url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
+ function(s) parsed.scheme = s; return "" end)
+ -- get authority
+ url = string.gsub(url, "^//([^/]*)", function(n)
+ parsed.authority = n
+ return ""
+ end)
+ -- get query stringing
+ url = string.gsub(url, "%?(.*)", function(q)
+ parsed.query = q
+ return ""
+ end)
+ -- get params
+ url = string.gsub(url, "%;(.*)", function(p)
+ parsed.params = p
+ return ""
+ end)
+ -- path is whatever was left
+ if url ~= "" then parsed.path = url end
+ local authority = parsed.authority
+ if not authority then return parsed end
+ authority = string.gsub(authority,"^([^@]*)@",
+ function(u) parsed.userinfo = u; return "" end)
+ authority = string.gsub(authority, ":([^:]*)$",
+ function(p) parsed.port = p; return "" end)
+ if authority ~= "" then parsed.host = authority end
+ local userinfo = parsed.userinfo
+ if not userinfo then return parsed end
+ userinfo = string.gsub(userinfo, ":([^:]*)$",
+ function(p) parsed.password = p; return "" end)
+ parsed.user = userinfo
+ return parsed
+end
+
+-----------------------------------------------------------------------------
+-- Rebuilds a parsed URL from its components.
+-- Components are protected if any reserved or unallowed characters are found
+-- Input
+-- parsed: parsed URL, as returned by parse
+-- Returns
+-- a stringing with the corresponding URL
+-----------------------------------------------------------------------------
+function build(parsed)
+ local ppath = parse_path(parsed.path or "")
+ local url = build_path(ppath)
+ if parsed.params then url = url .. ";" .. parsed.params end
+ if parsed.query then url = url .. "?" .. parsed.query end
+ local authority = parsed.authority
+ if parsed.host then
+ authority = parsed.host
+ if parsed.port then authority = authority .. ":" .. parsed.port end
+ local userinfo = parsed.userinfo
+ if parsed.user then
+ userinfo = parsed.user
+ if parsed.password then
+ userinfo = userinfo .. ":" .. parsed.password
+ end
+ end
+ if userinfo then authority = userinfo .. "@" .. authority end
+ end
+ if authority then url = "//" .. authority .. url end
+ if parsed.scheme then url = parsed.scheme .. ":" .. url end
+ if parsed.fragment then url = url .. "#" .. parsed.fragment end
+ -- url = string.gsub(url, "%s", "")
+ return url
+end
+
+-----------------------------------------------------------------------------
+-- Builds a absolute URL from a base and a relative URL according to RFC 2396
+-- Input
+-- base_url
+-- relative_url
+-- Returns
+-- corresponding absolute url
+-----------------------------------------------------------------------------
+function absolute(base_url, relative_url)
+ if base.type(base_url) == "table" then
+ base_parsed = base_url
+ base_url = build(base_parsed)
+ else
+ base_parsed = parse(base_url)
+ end
+ local relative_parsed = parse(relative_url)
+ if not base_parsed then return relative_url
+ elseif not relative_parsed then return base_url
+ elseif relative_parsed.scheme then return relative_url
+ else
+ relative_parsed.scheme = base_parsed.scheme
+ if not relative_parsed.authority then
+ relative_parsed.authority = base_parsed.authority
+ if not relative_parsed.path then
+ relative_parsed.path = base_parsed.path
+ if not relative_parsed.params then
+ relative_parsed.params = base_parsed.params
+ if not relative_parsed.query then
+ relative_parsed.query = base_parsed.query
+ end
+ end
+ else
+ relative_parsed.path = absolute_path(base_parsed.path or "",
+ relative_parsed.path)
+ end
+ end
+ return build(relative_parsed)
+ end
+end
+
+-----------------------------------------------------------------------------
+-- Breaks a path into its segments, unescaping the segments
+-- Input
+-- path
+-- Returns
+-- segment: a table with one entry per segment
+-----------------------------------------------------------------------------
+function parse_path(path)
+ local parsed = {}
+ path = path or ""
+ --path = string.gsub(path, "%s", "")
+ string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
+ for i = 1, table.getn(parsed) do
+ parsed[i] = unescape(parsed[i])
+ end
+ if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
+ if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
+ return parsed
+end
+
+-----------------------------------------------------------------------------
+-- Builds a path component from its segments, escaping protected characters.
+-- Input
+-- parsed: path segments
+-- unsafe: if true, segments are not protected before path is built
+-- Returns
+-- path: corresponding path stringing
+-----------------------------------------------------------------------------
+function build_path(parsed, unsafe)
+ local path = ""
+ local n = table.getn(parsed)
+ if unsafe then
+ for i = 1, n-1 do
+ path = path .. parsed[i]
+ path = path .. "/"
+ end
+ if n > 0 then
+ path = path .. parsed[n]
+ if parsed.is_directory then path = path .. "/" end
+ end
+ else
+ for i = 1, n-1 do
+ path = path .. protect_segment(parsed[i])
+ path = path .. "/"
+ end
+ if n > 0 then
+ path = path .. protect_segment(parsed[n])
+ if parsed.is_directory then path = path .. "/" end
+ end
+ end
+ if parsed.is_absolute then path = "/" .. path end
+ return path
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/table.save-0.94.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/table.save-0.94.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,183 @@
+--[[
+ Save Table to File/Stringtable
+ Load Table from File/Stringtable
+ v 0.94
+
+ Lua 5.1 compatible
+
+ Userdata and indices of these are not saved
+ Functions are saved via string.dump, so make sure it has no upvalues
+ References are saved
+ ----------------------------------------------------
+ table.save( table [, filename] )
+
+ Saves a table so it can be called via the table.load function again
+ table must a object of type 'table'
+ filename is optional, and may be a string representing a filename or true/1
+
+ table.save( table )
+ on success: returns a string representing the table (stringtable)
+ (uses a string as buffer, ideal for smaller tables)
+ table.save( table, true or 1 )
+ on success: returns a string representing the table (stringtable)
+ (uses io.tmpfile() as buffer, ideal for bigger tables)
+ table.save( table, "filename" )
+ on success: returns 1
+ (saves the table to file "filename")
+ on failure: returns as second argument an error msg
+ ----------------------------------------------------
+ table.load( filename or stringtable )
+
+ Loads a table that has been saved via the table.save function
+
+ on success: returns a previously saved table
+ on failure: returns as second argument an error msg
+ ----------------------------------------------------
+
+ chillcode, http://lua-users.org/wiki/SaveTableToFile
+ Licensed under the same terms as Lua itself.
+]]--
+do
+ -- declare local variables
+ --// exportstring( string )
+ --// returns a "Lua" portable version of the string
+ local function exportstring( s )
+ s = string.format( "%q",s )
+ -- to replace
+ s = string.gsub( s,"\\\n","\\n" )
+ s = string.gsub( s,"\r","\\r" )
+ s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
+ return s
+ end
+
+ --// The Save Function
+ function table.save( tbl,filename )
+ local charS,charE = " ","\n"
+ local file,err
+ -- create a pseudo file that writes to a string and return the string
+ if not filename then
+ file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
+ charS,charE = "",""
+ -- write table to tmpfile
+ elseif filename == true or filename == 1 then
+ charS,charE,file = "","",io.tmpfile()
+ -- write table to file
+ -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error
+ else
+ file,err = io.open( filename, "w" )
+ if err then return _,err end
+ end
+ -- initiate variables for save procedure
+ local tables,lookup = { tbl },{ [tbl] = 1 }
+ file:write( "return {"..charE )
+ for idx,t in ipairs( tables ) do
+ if filename and filename ~= true and filename ~= 1 then
+ file:write( "-- Table: {"..idx.."}"..charE )
+ end
+ file:write( "{"..charE )
+ local thandled = {}
+ for i,v in ipairs( t ) do
+ thandled[i] = true
+ -- escape functions and userdata
+ if type( v ) ~= "userdata" then
+ -- only handle value
+ if type( v ) == "table" then
+ if not lookup[v] then
+ table.insert( tables, v )
+ lookup[v] = #tables
+ end
+ file:write( charS.."{"..lookup[v].."},"..charE )
+ elseif type( v ) == "function" then
+ file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
+ else
+ local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
+ file:write( charS..value..","..charE )
+ end
+ end
+ end
+ for i,v in pairs( t ) do
+ -- escape functions and userdata
+ if (not thandled[i]) and type( v ) ~= "userdata" then
+ -- handle index
+ if type( i ) == "table" then
+ if not lookup[i] then
+ table.insert( tables,i )
+ lookup[i] = #tables
+ end
+ file:write( charS.."[{"..lookup[i].."}]=" )
+ else
+ local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
+ file:write( charS..index.."=" )
+ end
+ -- handle value
+ if type( v ) == "table" then
+ if not lookup[v] then
+ table.insert( tables,v )
+ lookup[v] = #tables
+ end
+ file:write( "{"..lookup[v].."},"..charE )
+ elseif type( v ) == "function" then
+ file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
+ else
+ local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
+ file:write( value..","..charE )
+ end
+ end
+ end
+ file:write( "},"..charE )
+ end
+ file:write( "}" )
+ -- Return Values
+ -- return stringtable from string
+ if not filename then
+ -- set marker for stringtable
+ return file.str.."--|"
+ -- return stringttable from file
+ elseif filename == true or filename == 1 then
+ file:seek ( "set" )
+ -- no need to close file, it gets closed and removed automatically
+ -- set marker for stringtable
+ return file:read( "*a" ).."--|"
+ -- close file and return 1
+ else
+ file:close()
+ return 1
+ end
+ end
+
+ --// The Load Function
+ function table.load( sfile )
+ -- catch marker for stringtable
+ if string.sub( sfile,-3,-1 ) == "--|" then
+ tables,err = loadstring( sfile )
+ else
+ tables,err = loadfile( sfile )
+ end
+
+ if err then return _,err end
+
+ tables = tables()
+
+ for idx = 1,#tables do
+ local tolinkv,tolinki = {},{}
+ for i,v in pairs( tables[idx] ) do
+ if type( v ) == "table" and tables[v[1]] then
+ table.insert( tolinkv,{ i,tables[v[1]] } )
+ end
+ if type( i ) == "table" and tables[i[1]] then
+ table.insert( tolinki,{ i,tables[i[1]] } )
+ end
+ end
+ -- link values, first due to possible changes of indices
+ for _,v in ipairs( tolinkv ) do
+ tables[idx][v[1]] = v[2]
+ end
+ -- link indices
+ for _,v in ipairs( tolinki ) do
+ tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil
+ end
+ end
+ return tables[1]
+ end
+ -- close do
+end
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/test.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/test.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,31 @@
+
+require("ipcalc");
+
+
+print(string.format("hasbit(%08x, %08x) = %s", 0x12345678, 0x00001000, tostring(hasbit(0x12345678, 0x00004000))));
+
+print(string.format("(%08x & %08x) = %08x", 0x12345678, 0xfffff000, andL(0x12345678, 0x000fffff)));
+
+m =13
+print(string.format("%d netmask=%08x hostmask=%08x", m, bits_to_netmask(m), bits_to_hostmask(m)));
+
+require("ipcalc");
+
+local r = cidr_to_net("213.130.11.129/23");
+
+
+--[[
+r.host 0.0.1.129
+r.bits 23
+r.broadcast 213.130.11.255
+r.net 213.130.10.0
+r.mask 255.255.254.0
+r.ip 213.130.11.129
+r.cidr 213.130.11.129/23
+]]
+
+
+
+
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/utils.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/utils.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,328 @@
+--[[
+ tdump(table_to_dump)
+ return text dump of table
+]]
+
+function tdump(t)
+ local function dmp(t, l, k)
+ local ret = "";
+ if type(t) == "table" then
+ ret = ret .. string.format("%s%s:", string.rep(" ", l*2), tostring(k)) .. "\n";
+ for k, v in pairs(t) do
+ if k ~= "_parent" then
+ ret = ret .. dmp(v, l+1, k);
+ end
+ end
+ else
+ ret = ret .. string.format("%s%s:%s", string.rep(" ", l*2), tostring(k), tostring(t)) .. "\n";
+ end
+ return (ret);
+ end
+ return dmp(t, 1, "root");
+end
+
+--[[
+ xmldump(table_to_dump)
+ return XML subtree of table
+]]
+
+function xmldump(t)
+
+ local function xatrdmp(t)
+ local ret = '';
+
+ for k, v in pairs(t) do
+ ret = ret .. string.format(" %s=\"%s\"", tostring(k), tostring(v));
+ end
+
+ return ret;
+ end
+
+ local function xdmp(t, l)
+ local ret = '';
+ local enum = 0;
+ local name = t._name or '';
+ local attrs = '';
+ local childs = '';
+ local brk = nil;
+
+ if t._attr then
+ attrs = attrs .. xatrdmp(t._attr);
+ end
+
+
+ if t._children then
+ for k, v in ipairs(t._children) do
+ childs = childs .. xdmp(v, l+1);
+ end
+
+ if table.maxn (t._children) > 1 then
+ brk = 1;
+ elseif table.maxn (t._children) == 1 and
+ t._children[1]._type ~= "TEXT" then
+ brk = 1;
+ end
+ end
+
+ if t._type == "ELEMENT" then
+ if brk then
+ ret = ret ..
+ string.format("%s<%s%s>\n", string.rep(" ", l*4), name, attrs) ..
+ childs ..
+ string.format("%s</%s>\n", string.rep(" ", l*4), name);
+ else
+ ret = ret ..
+ string.format("%s<%s%s>", string.rep(" ", l*4), name, attrs) ..
+ childs ..
+ string.format("</%s>\n", name);
+ end
+ elseif t._type == "TEXT" then
+ ret = ret .. t._text;
+ elseif t._type == "ROOT" then
+ ret = childs;
+ elseif t._type == "COMMENT" then
+ ret = ret ..
+ string.format("%s<!-- %s -->\n", string.rep(" ", l*4), t._text);
+-- else
+-- print("Parse Error Unknow type \"" .. (t._type or "(nil)") .. "\"");
+ end
+
+ -- print(ret);
+ return ret;
+ end
+
+ return xdmp(t, -1);
+end
+
+
+
+--[[
+ read_file(_file)
+ return data from file
+]]
+function read_file(_file)
+ local xml;
+
+ if (_debug) then
+ io.write ( "File: ".._file.."\n" )
+ end
+
+ local f, e = io.open(_file, "r")
+ if f then
+ xml = f:read("*a")
+ else
+ return ("Can't open file " .. _file);
+ end
+
+ return xml;
+end
+
+function inc(_file)
+ return read_file(_file);
+end
+
+function load_file(_file)
+ h = domHandler();
+ x = xmlParser(h);
+ index = 1
+
+ x.options.expandEntities = 1; -- nil;
+ x:parse(read_file(_file));
+
+ return (h.root);
+end
+
+function save_file(_file, _data)
+ local out, e = io.open(_file, "w");
+ if out then
+ out:write(_data);
+ assert(out:close());
+ else
+ print(e);
+ return (nil);
+ end
+
+ return (true);
+end
+
+function checked(v)
+ if (v and v ~= "" and v ~= "false") then
+ return "checked";
+ end
+ return "";
+end
+
+function field(v)
+ if (v and v ~= "") then
+ return v;
+ end
+ return "";
+end
+
+function conf_table(id, header, rootpath, fields)
+
+ local ret =
+ "<div id=\"" .. id .. "\" class=\"yui3-module boxitem\">\n" ..
+ " <div class=\"yui3-hd\">\n" ..
+ " <h4>" .. header .."</h4>\n" ..
+ " </div>\n" ..
+ " <div class=\"yui3-bd\">\n" ..
+ " <form method=\"POST\" target=\"/cmd.xml\" onchange=\"document.getElementById('" .. id .. "_update_button').disabled = false; return true;\">\n" ..
+ " <input type=\"hidden\" name=\"path\" value=\"" .. rootpath .."\" />\n" ..
+ " <input type=\"hidden\" name=\"cmd\" value=\"setmany\" />\n" ..
+ " <table>\n";
+
+
+ for i,v in ipairs(fields) do
+ if v.type == "attr" then
+ local _, _, nodestr, attrstr = string.find(v.node, "(.-)%:(.*)");
+
+ print(string.format("node='%s' attr='%s'", nodestr or "(no node)", attrstr or "(no attr)"));
+
+ if not nodestr then
+ nodestr = rootpath;
+ else
+ nodestr = rootpath .. "." .. nodestr;
+ end
+
+ if not attrstr then
+ ret = ret .. "Error parsing attr fileld at path " .. v.node;
+ else
+
+ attrvalue = c:getNode(nodestr):attr(attrstr) or
+ "Error getting attribute value of " .. nodestr .. ":attr(" .. attrstr .. ")";
+ local inserted = "";
+ if v.htmltype == "checkbox" then
+ inserted = checked(attrvalue);
+ elseif v.htmltype == "text" then
+ inserted = " value=\"" .. attrvalue .. "\"";
+ else
+ inserted = "Unknown htmltype " .. v.htmltype;
+ end
+ ret = ret ..
+ " <tr>\n" ..
+ " <td>" .. v.label .. ":</td>\n" ..
+ " <td><input name=\"smattr:" .. v.node .. "\" " ..
+ "type=\"" .. v.htmltype .. "\" " ..
+ inserted ..
+ " onchange=\"" ..
+ "document.getElementById(" ..
+ "'" .. id .. "_update_button'" ..
+ ").disabled = false; return true;\"/></td>\n" ..
+ " </tr>\n";
+ end
+ elseif v.type == "node" then
+ local nodestr = v.node;
+ if not nodestr then
+ nodestr = rootpath;
+ else
+ nodestr = rootpath .. "." .. nodestr;
+ end
+
+ local n = c:getNode(nodestr);
+ if n then
+ nodevalue = n:value() or "";
+ else
+ nodevalue = "Error: node " .. nodestr .. " not found";
+ end
+
+ nodevalue = nodevalue:gsub("\"",""");
+
+ ret = ret ..
+ " <tr>\n" ..
+ " <td>" .. v.label .. ":</td>\n" ..
+ " <td><input type=\"" .. v.htmltype .. "\" name=\"sm:" .. v.node .. "\" value=\"" ..
+ nodevalue ..
+ "\" onchange=\"document.getElementById(" ..
+ "'" .. id .. "_update_button'" ..
+ ").disabled = false; return true;\"/></td>\n" ..
+ " </tr>\n";
+ end
+ end
+
+ ret = ret ..
+ " <tr>\n" ..
+ " <td> </td>\n" ..
+ " <td><input id=\"" .. id .. "_update_button\" type=\"button\" name=\"Update\" value=\"Update\" disabled onclick=\"" ..
+ "send_update(this.form, function(x) { document.getElementById('" .. id .. "_update_button').disabled = true; })" ..
+ "\"/></td>\n" ..
+ " </tr>\n" ..
+ " </table>\n" ..
+ " </form>\n" ..
+ " </div>\n" ..
+ "</div>\n";
+
+ return (ret);
+end
+
+function peritem(item, sub)
+ if type(item) == "table" then
+
+ for k, v in pairs(item) do
+ sub(v);
+ end
+ else
+ sub(item);
+ end
+end
+
+function kldload(module)
+ function kldload_one(module)
+ if debug then
+ print("kldstat -q -m " .. module .. " || kldload " .. module);
+ end
+ os.execute("kldstat -q -m " .. module .. " || kldload " .. module);
+ end
+ peritem(module, kldload_one);
+end
+
+function strip_quote (str)
+ str = str:gsub("^\"(.*)\"$", "%1");
+ str = str:gsub("^\'(.*)\'$", "%1");
+ return str;
+end
+
+function parse_kv_file (ar, file)
+ local err = nil;
+ if not file then
+ return "Filename required";
+ end
+
+ if type(ar) ~= "table" then
+ return "First argument must be table";
+ end
+
+ local f = io.open(file);
+ if not f then
+ return "Can't open \"" .. file .. "\"\n";
+ end
+
+ local count = 0;
+ while true do
+ local line = f:read('*line');
+ if line == nil then break end -- EOF
+ if count > 100 then
+ -- to much lines
+ err = "Lines count more than 100 \"" .. file .. "\n";
+ break;
+ end
+
+ line = line:gsub("#.*$", ""); -- Strip comments
+ line = line:gsub("%s*$", ""); -- Strip whitespaces
+
+ if line ~= "" then -- Do only if line not empty
+ match, _, name, value = line:find("^(.+)=(.+)%s*$");
+ if not match then
+ err = "Wrong format in \"" .. file .. "\n";
+ break;
+ end
+ ar[strip_quote(name)] = strip_quote(value);
+ end
+
+ count = count + 1;
+ end
+
+ f:close();
+ return err;
+end
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/files/etc/www/lib/xml.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/files/etc/www/lib/xml.lua Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,472 @@
+---
+-- Overview:
+-- =========
+--
+-- This module provides a non-validating XML stream parser in Lua.
+--
+-- Features:
+-- =========
+--
+-- * Tokenises well-formed XML (relatively robustly)
+-- * Flexible handler based event api (see below)
+-- * Parses all XML Infoset elements - ie.
+-- - Tags
+-- - Text
+-- - Comments
+-- - CDATA
+-- - XML Decl
+-- - Processing Instructions
+-- - DOCTYPE declarations
+-- * Provides limited well-formedness checking
+-- (checks for basic syntax & balanced tags only)
+-- * Flexible whitespace handling (selectable)
+-- * Entity Handling (selectable)
+--
+-- Limitations:
+-- ============
+--
+-- * Non-validating
+-- * No charset handling
+-- * No namespace support
+-- * Shallow well-formedness checking only (fails
+-- to detect most semantic errors)
+--
+-- API:
+-- ====
+--
+-- The parser provides a partially object-oriented API with
+-- functionality split into tokeniser and hanlder components.
+--
+-- The handler instance is passed to the tokeniser and receives
+-- callbacks for each XML element processed (if a suitable handler
+-- function is defined). The API is conceptually similar to the
+-- SAX API but implemented differently.
+--
+-- The following events are generated by the tokeniser
+--
+-- handler:start - Start Tag
+-- handler:end - End Tag
+-- handler:text - Text
+-- handler:decl - XML Declaration
+-- handler:pi - Processing Instruction
+-- handler:comment - Comment
+-- handler:dtd - DOCTYPE definition
+-- handler:cdata - CDATA
+--
+-- The function prototype for all the callback functions is
+--
+-- callback(val,attrs,start,end)
+--
+-- where attrs is a table and val/attrs are overloaded for
+-- specific callbacks - ie.
+--
+-- Callback val attrs (table)
+-- -------- --- -------------
+-- start name { attributes (name=val).. }
+-- end name nil
+-- text <text> nil
+-- cdata <text> nil
+-- decl "xml" { attributes (name=val).. }
+-- pi pi name { attributes (if present)..
+-- _text = <PI Text>
+-- }
+-- comment <text> nil
+-- dtd root element { _root = <Root Element>,
+-- _type = SYSTEM|PUBLIC,
+-- _name = <name>,
+-- _uri = <uri>,
+-- _internal = <internal dtd>
+-- }
+--
+-- (start & end provide the character positions of the start/end
+-- of the element)
+--
+-- XML data is passed to the parser instance through the 'parse'
+-- method (Nore: must be passed a single string currently)
+--
+-- Options
+-- =======
+--
+-- Parser options are controlled through the 'self.options' table.
+-- Available options are -
+--
+-- * stripWS
+--
+-- Strip non-significant whitespace (leading/trailing)
+-- and do not generate events for empty text elements
+--
+-- * expandEntities
+--
+-- Expand entities (standard entities + single char
+-- numeric entities only currently - could be extended
+-- at runtime if suitable DTD parser added elements
+-- to table (see obj._ENTITIES). May also be possible
+-- to expand multibyre entities for UTF-8 only
+--
+-- * errorHandler
+--
+-- Custom error handler function
+--
+-- NOTE: Boolean options must be set to 'nil' not '0'
+--
+-- Usage
+-- =====
+--
+-- Create a handler instance -
+--
+-- h = { start = function(t,a,s,e) .... end,
+-- end = function(t,a,s,e) .... end,
+-- text = function(t,a,s,e) .... end,
+-- cdata = text }
+--
+-- (or use predefined handler - see handler.lua)
+--
+-- Create parser instance -
+--
+-- p = xmlParser(h)
+--
+-- Set options -
+--
+-- p.options.xxxx = nil
+--
+-- Parse XML data -
+--
+-- xmlParser:parse("<?xml... ")
+-- License:
+-- ========
+--
+-- This code is freely distributable under the terms of the Lua license
+-- (http://www.lua.org/copyright.html)
+--
+-- History
+-- =======
+-- Added parameter parseAttributes (boolean) in xmlParser.parse method
+-- If true, tag attributtes are parsed. The default value is true.
+-- by Manoel Campos (http://manoelcampos.com)
+--
+-- $Id: xml.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+-- $Log: xml.lua,v $
+-- Revision 1.1.1.1 2001/11/28 06:11:33 paulc
+-- Initial Import
+--
+-- at author Paul Chakravarti (paulc at passtheaardvark.com)<p/>
+
+
+---Parses a XML string
+-- at param handler Handler object to be used to convert the XML string
+--to another formats. @see handler.lua
+xmlParser = function(handler)
+ local obj = {}
+ -- Public attributes
+
+ obj.options = {
+ stripWS = 1,
+ expandEntities = 1,
+ errorHandler = function(err,pos)
+ error(format("%s [char=%d]\n",
+ err or "Parse Error",pos))
+ end,
+ }
+
+ -- Public methods
+
+ obj.parse = function(self, str, parseAttributes)
+ if parseAttributes == nil then
+ parseAttributes = true
+ end
+ self._handler.parseAttributes = parseAttributes
+
+ local match,endmatch,pos = 0,0,1
+ local text,endt1,endt2,tagstr,tagname,attrs,starttext,endtext
+ local errstart,errend,extstart,extend
+ while match do
+ -- Get next tag (first pass - fix exceptions below)
+ match,endmatch,text,endt1,tagstr,endt2 = string.find(str,self._XML,pos)
+ if not match then
+ if string.find(str,self._WS,pos) then
+ -- No more text - check document complete
+ if table.getn(self._stack) ~= 0 then
+ self:_err(self._errstr.incompleteXmlErr,pos)
+ else
+ break
+ end
+ else
+ -- Unparsable text
+ self:_err(self._errstr.xmlErr,pos)
+ end
+ end
+ -- Handle leading text
+ starttext = match
+ endtext = match + string.len(text) - 1
+ match = match + string.len(text)
+ text = self:_parseEntities(self:_stripWS(text))
+ if text ~= "" and self._handler.text then
+ self._handler:text(text,nil,match,endtext)
+ end
+ -- Test for tag type
+ if string.find(string.sub(tagstr,1,5),"?xml%s") then
+ -- XML Declaration
+ match,endmatch,text = string.find(str,self._PI,pos)
+ if not match then
+ self:_err(self._errstr.declErr,pos)
+ end
+ if match ~= 1 then
+ -- Must be at start of doc if present
+ self:_err(self._errstr.declStartErr,pos)
+ end
+ tagname,attrs = self:_parseTag(text)
+ -- TODO: Check attributes are valid
+ -- Check for version (mandatory)
+ if attrs.version == nil then
+ self:_err(self._errstr.declAttrErr,pos)
+ end
+ if self._handler.decl then
+ self._handler:decl(tagname,attrs,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,1) == "?" then
+ -- Processing Instruction
+ match,endmatch,text = string.find(str,self._PI,pos)
+ if not match then
+ self:_err(self._errstr.piErr,pos)
+ end
+ if self._handler.pi then
+ -- Parse PI attributes & text
+ tagname,attrs = self:_parseTag(text)
+ local pi = string.sub(text,string.len(tagname)+1)
+ if pi ~= "" then
+ if attrs then
+ attrs._text = pi
+ else
+ attrs = { _text = pi }
+ end
+ end
+ self._handler:pi(tagname,attrs,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,3) == "!--" then
+ -- Comment
+ match,endmatch,text = string.find(str,self._COMMENT,pos)
+ if not match then
+ self:_err(self._errstr.commentErr,pos)
+ end
+ if self._handler.comment then
+ text = self:_parseEntities(self:_stripWS(text))
+ self._handler:comment(text,next,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,8) == "!DOCTYPE" then
+ -- DTD
+ match,endmatch,attrs = self:_parseDTD(string,pos)
+ if not match then
+ self:_err(self._errstr.dtdErr,pos)
+ end
+ if self._handler.dtd then
+ self._handler:dtd(attrs._root,attrs,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,8) == "![CDATA[" then
+ -- CDATA
+ match,endmatch,text = string.find(str,self._CDATA,pos)
+ if not match then
+ self:_err(self._errstr.cdataErr,pos)
+ end
+ if self._handler.cdata then
+ self._handler:cdata(text,nil,match,endmatch)
+ end
+ else
+ -- Normal tag
+
+ -- Need theck for embedded '>' in attribute value and extend
+ -- match recursively if necessary eg. <tag attr="123>456">
+
+ while 1 do
+ errstart,errend = string.find(tagstr,self._ATTRERR1)
+ if errend == nil then
+ errstart,errend = string.find(tagstr,self._ATTRERR2)
+ if errend == nil then
+ break
+ end
+ end
+ extstart,extend,endt2 = string.find(str,self._TAGEXT,endmatch+1)
+ tagstr = tagstr .. string.sub(string,endmatch,extend-1)
+ if not match then
+ self:_err(self._errstr.xmlErr,pos)
+ end
+ endmatch = extend
+ end
+
+ -- Extract tagname/attrs
+
+ tagname,attrs = self:_parseTag(tagstr)
+
+ if (endt1=="/") then
+ -- End tag
+ if self._handler.endtag then
+ if attrs then
+ -- Shouldnt have any attributes in endtag
+ self:_err(format("%s (/%s)",
+ self._errstr.endTagErr,
+ tagname)
+ ,pos)
+ end
+ if table.remove(self._stack) ~= tagname then
+ self:_err(format("%s (/%s)",
+ self._errstr.unmatchedTagErr,
+ tagname)
+ ,pos)
+ end
+ self._handler:endtag(tagname,nil,match,endmatch)
+ end
+ else
+ -- Start Tag
+ table.insert(self._stack,tagname)
+ if self._handler.starttag then
+ self._handler:starttag(tagname,attrs,match,endmatch)
+ end
+ -- Self-Closing Tag
+ if (endt2=="/") then
+ table.remove(self._stack)
+ if self._handler.endtag then
+ self._handler:endtag(tagname,nil,match,endmatch)
+ end
+ end
+ end
+ end
+ pos = endmatch + 1
+ end
+ end
+
+ -- Private attributes/functions
+
+ obj._handler = handler
+ obj._stack = {}
+
+ obj._XML = '^([^<]*)<(%/?)([^>]-)(%/?)>'
+ obj._ATTR1 = '([%w-:_]+)%s*=%s*"(.-)"'
+ obj._ATTR2 = '([%w-:_]+)%s*=%s*\'(.-)\''
+ obj._CDATA = '<%!%[CDATA%[(.-)%]%]>'
+ obj._PI = '<%?(.-)%?>'
+ obj._COMMENT = '<!%-%-(.-)%-%->'
+ obj._TAG = '^(.-)%s.*'
+ obj._LEADINGWS = '^%s+'
+ obj._TRAILINGWS = '%s+$'
+ obj._WS = '^%s*$'
+ obj._DTD1 = '<!DOCTYPE%s+(.-)%s+(SYSTEM)%s+["\'](.-)["\']%s*(%b[])%s*>'
+ obj._DTD2 = '<!DOCTYPE%s+(.-)%s+(PUBLIC)%s+["\'](.-)["\']%s+["\'](.-)["\']%s*(%b[])%s*>'
+ obj._DTD3 = '<!DOCTYPE%s+(.-)%s*(%b[])%s*>'
+ obj._DTD4 = '<!DOCTYPE%s+(.-)%s+(SYSTEM)%s+["\'](.-)["\']%s*>'
+ obj._DTD5 = '<!DOCTYPE%s+(.-)%s+(PUBLIC)%s+["\'](.-)["\']%s+["\'](.-)["\']%s*>'
+
+ obj._ATTRERR1 = '=%s*"[^"]*$'
+ obj._ATTRERR2 = '=%s*\'[^\']*$'
+ obj._TAGEXT = '(%/?)>'
+
+ obj._ENTITIES = { ["<"] = "<",
+ [">"] = ">",
+ ["&"] = "&",
+ ["""] = '"',
+ ["'"] = "'",
+ ["&#(%d+);"] = function (x)
+ local d = tonumber(x)
+ if d >= 0 and d < 256 then
+ return string.char(d)
+ else
+ return "&#"..d..";"
+ end
+ end,
+ ["&#x(%x+);"] = function (x)
+ local d = tonumber(x,16)
+ if d >= 0 and d < 256 then
+ return string.char(d)
+ else
+ return "&#x"..x..";"
+ end
+ end,
+ }
+
+ obj._err = function(self,err,pos)
+ if self.options.errorHandler then
+ self.options.errorHandler(err,pos)
+ end
+ end
+
+ obj._errstr = { xmlErr = "Error Parsing XML",
+ declErr = "Error Parsing XMLDecl",
+ declStartErr = "XMLDecl not at start of document",
+ declAttrErr = "Invalid XMLDecl attributes",
+ piErr = "Error Parsing Processing Instruction",
+ commentErr = "Error Parsing Comment",
+ cdataErr = "Error Parsing CDATA",
+ dtdErr = "Error Parsing DTD",
+ endTagErr = "End Tag Attributes Invalid",
+ unmatchedTagErr = "Unbalanced Tag",
+ incompleteXmlErr = "Incomplete XML Document",
+ }
+
+ obj._stripWS = function(self,s)
+ if self.options.stripWS then
+ s = string.gsub(s,'^%s+','')
+ s = string.gsub(s,'%s+$','')
+ end
+ return s
+ end
+
+ obj._parseEntities = function(self,s)
+ if self.options.expandEntities then
+ --for k,v in self._ENTITIES do
+ for k,v in pairs(self._ENTITIES) do
+ --print (k, v)
+ s = string.gsub(s,k,v)
+ end
+ end
+ return s
+ end
+
+ obj._parseDTD = function(self,s,pos)
+ -- match,endmatch,root,type,name,uri,internal
+ local m,e,r,t,n,u,i
+ m,e,r,t,u,i = string.find(s,self._DTD1,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_uri=u,_internal=i}
+ end
+ m,e,r,t,n,u,i = string.find(s,self._DTD2,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_name=n,_uri=u,_internal=i}
+ end
+ m,e,r,i = string.find(s,self._DTD3,pos)
+ if m then
+ return m,e,{_root=r,_internal=i}
+ end
+ m,e,r,t,u = string.find(s,self._DTD4,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_uri=u}
+ end
+ m,e,r,t,n,u = string.find(s,self._DTD5,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_name=n,_uri=u}
+ end
+ return nil
+ end
+
+ obj._parseTag = function(self,s)
+ local attrs = {}
+ local tagname = string.gsub(s,self._TAG,'%1')
+ string.gsub(s,self._ATTR1,function (k,v)
+ attrs[string.lower(k)]=self:_parseEntities(v)
+ attrs._ = 1
+ end)
+ string.gsub(s,self._ATTR2,function (k,v)
+ attrs[string.lower(k)]=self:_parseEntities(v)
+ attrs._ = 1
+ end)
+ if attrs._ then
+ attrs._ = nil
+ else
+ attrs = nil
+ end
+ return tagname,attrs
+ end
+
+ return obj
+
+end
+
+
diff -r ebed26f4cae2 -r 367c29234e4c profiles/lua_web_ui/profile.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/profiles/lua_web_ui/profile.mk Thu Sep 20 15:21:54 2012 +0300
@@ -0,0 +1,13 @@
+
+
+
+# Requirement of other profiles
+# XXX not yet supported, TARGET_PROFILES used as simple list
+#TARGET_PROFILES+=shttpd
+
+WORLD_SUBDIRS_ZROUTER+= \
+ target/usr.bin/lua/
+
+WORLD_SUBDIRS_USR_SBIN+= \
+ tcpdump
+
More information about the Zrouter-src
mailing list