NIU: More pages
authorSteven Barth <steven@midlink.org>
Tue, 10 Nov 2009 16:02:48 +0000 (16:02 +0000)
committerSteven Barth <steven@midlink.org>
Tue, 10 Nov 2009 16:02:48 +0000 (16:02 +0000)
14 files changed:
build/setup.lua
libs/cbi/luasrc/cbi.lua
libs/uci/luasrc/model/uci.lua
libs/web/luasrc/dispatcher.lua
modules/niu/luasrc/controller/niu/dashboard.lua
modules/niu/luasrc/controller/niu/network.lua
modules/niu/luasrc/controller/niu/system.lua
modules/niu/luasrc/model/cbi/niu/network/lan.lua
modules/niu/luasrc/model/cbi/niu/system/reboot.lua [new file with mode: 0644]
modules/niu/luasrc/view/niu/network.htm
modules/niu/luasrc/view/niu/network/warn_ip_change.htm [new file with mode: 0644]
modules/niu/luasrc/view/niu/system/backup.htm [new file with mode: 0644]
modules/niu/luasrc/view/niu/system/reboot.htm [new file with mode: 0644]
modules/niu/luasrc/view/niu/system/upgrade.htm [new file with mode: 0644]

index 4a771540da633f0bbb84ba9631c027a165c7cefc..f374da90f7967c4e9fce752ac4111062ccda798c 100644 (file)
@@ -12,6 +12,9 @@ uci_model.cursor_state = function()
        return uci_core.cursor(SYSROOT .. "/etc/config", SYSROOT .. "/var/state")
 end
 
+uci_model.inst = uci_model.cursor()
+uci_model.inst_state = uci_model.cursor_state()
+
 -- override uvl access
 local uvl_model = require "luci.uvl"
 local uvl_init  = uvl_model.UVL.__init__
index f6a2694b2ca3fa9664291aa6813d0a7eb2e72e99..5a1d923853381cb8b8cbe952b3dc3f806d83af9e 100644 (file)
@@ -222,6 +222,12 @@ function Node.__init__(self, title, description)
 end
 
 -- hook helper
+function Node._run_hook(self, hook)
+       if type(self[hook]) == "function" then
+               return self[hook](self)
+       end 
+end
+
 function Node._run_hooks(self, ...)
        local f
        local r = false
@@ -528,9 +534,9 @@ function Delegator.add(self, name, node)
 end
 
 function Delegator.insert_after(self, name, after)
-       local n = #self.chain
+       local n = #self.chain + 1
        for k, v in ipairs(self.chain) do
-               if v == state then
+               if v == after then
                        n = k + 1
                        break
                end
@@ -599,8 +605,7 @@ function Delegator.parse(self, ...)
                return FORM_NODATA
        elseif stat > FORM_PROCEED 
        and (not newcurrent or not self:get(newcurrent)) then
-               self:_run_hooks("on_done")
-               return FORM_DONE
+               return self:_run_hook("on_done") or FORM_DONE
        else
                self.current = newcurrent or self.current
                self.active = self:get(self.current)
index c927b4ca5ab0a48a956b8c41d00f78acbe61b1cd..66bd0a026ee55634a66ea2c2460158e7c546c48b 100644 (file)
@@ -58,7 +58,10 @@ function cursor_state()
 end
 
 
-local Cursor = getmetatable(cursor())
+inst = cursor()
+inst_state = cursor_state()
+
+local Cursor = getmetatable(inst)
 
 --- Applies UCI configuration changes
 -- @param configlist           List of UCI configurations
index e3d7ec974806449a1299a4652f85998fc83440e0..8b7cdb8286b5391f668641339285baccc936cd6e 100644 (file)
@@ -34,6 +34,7 @@ local nixio = require "nixio", require "nixio.util"
 
 module("luci.dispatcher", package.seeall)
 context = util.threadlocal()
+uci = require "luci.model.uci"
 
 authenticator = {}
 
index e3270e4c665142cc4bfec89fca907e279d39b598..f6c8939808081d1815b474f20623b95163ce05e8 100644 (file)
@@ -36,8 +36,6 @@ function dashboard()
        local tpl = require "luci.template"
        local utl = require "luci.util"
        local uci = require "luci.model.uci"
-       local str = require "luci.store"
-       str.uci_state = str.uci_state or uci.cursor()
 
        local nds = dsp.node("niu").nodes
        tpl.render("niu/dashboard", {utl = utl, nodes = nds, dsp = dsp, tpl = tpl}) 
index cafed256792517d0d8ae1f2307e69697df060a9f..36aff630d70a3ece509f60c412b2dd5f4b2d03a7 100644 (file)
@@ -16,17 +16,21 @@ local req = require
 module "luci.controller.niu.network"
 
 function index()
-       entry({"niu", "network"}, nil, "Network").dbtemplate = "niu/network"
-
-       entry({"niu", "network", "lan"}, 
-       cbi("niu/network/lan", {on_success_to={"niu"}}), "Configure LAN", 10)
+       entry({"niu", "network"}, nil, "Network", 10).dbtemplate = "niu/network"
 
        entry({"niu", "network", "wan"}, 
-       cbi("niu/network/wan", {on_success_to={"niu"}}), "Configure Internet", 20)
+       cbi("niu/network/wan", {on_success_to={"niu"}}), "Configure Internet Connection", 10)
+
+       entry({"niu", "network", "lan"}, 
+       cbi("niu/network/lan", {on_success_to={"niu"}}), "Configure Local Network", 20)
        
-       entry({"niu", "network", "assign"}, cbi("niu/network/assign",
-        {on_success_to={"niu"}}), "Address Assignment", 30)
+       uci.inst_state:foreach("dhcp", "dhcp", function(s)
+               if s.interface == "lan" and s.ignore ~= "1" then 
+                       entry({"niu", "network", "assign"}, cbi("niu/network/assign",
+                               {on_success_to={"niu"}}), "Assign local addresses", 30)
+               end
+       end)
        
        entry({"niu", "network", "routes"},  cbi("niu/network/routes",
-        {on_success_to={"niu"}}), "Custom Routing", 40)
+        {on_success_to={"niu"}}), "Assign custom routes", 40)
 end
index 45f7cb615276559d7d5ec3305d616a20c0acfaa5..5ffed306b0bb9c1c890f188c3e1763a5b84d7518 100644 (file)
@@ -12,56 +12,249 @@ You may obtain a copy of the License at
 $Id$
 ]]--
 
-local require, pairs, unpack = require, pairs, unpack
+local require, pairs, unpack, tonumber = require, pairs, unpack, tonumber
 module "luci.controller.niu.system"
 
 function index()
-       entry({"niu", "system"}, nil, "System").dbtemplate = "niu/system"
+       entry({"niu", "system"}, nil, "System", 20).dbtemplate = "niu/system"
 
        entry({"niu", "system", "general"}, 
-       cbi("niu/system/general", {on_success_to={"niu"}}), "General", 10)
+       cbi("niu/system/general", {on_success_to={"niu"}}), "Configure Device", 10)
        
-       entry({"niu", "system", "backup"}, call("backup"), "Backup Settings", 20)
+       entry({"niu", "system", "backup"}, call("backup"), "Backup or Restore Settings", 20)
+       entry({"niu", "system", "upgrade"}, call("upgrade"), "Upgrade Firmware", 40)
 end
 
 function backup()
-       local os = require "os"
-       local uci = require "luci.model.uci".cursor()
+       local dsp = require "luci.dispatcher"
+       local os, io = require "os", require "io"
+       local uci = require "luci.model.uci".inst
        local nixio, nutl = require "nixio", require "nixio.util"
        local fs = require "nixio.fs"
        local http = require "luci.http"
+       local tpl = require "luci.template"
        
-       
-       local call = {"/bin/tar", "-cz"}
-       for k, v in pairs(uci:get_all("luci", "flash_keep")) do
-               if k:byte() ~= 46 then  -- k[1] ~= "."
-                       nutl.consume(fs.glob(v), call)
+       local restore_fpi 
+       http.setfilehandler(
+               function(meta, chunk, eof)
+                       if not restore_fpi then
+                               restore_fpi = io.popen("tar -xzC/ >/dev/null 2>&1", "w")
+                       end
+                       if chunk then
+                               restore_fpi:write(chunk)
+                       end
+                       if eof then
+                               restore_fpi:close()
+                       end
                end
-       end
+       )
        
+       local reset_avail = (fs.readfile("/proc/mtd") or ""):find('"rootfs_data"')
+       local upload = http.formvalue("archive")
+       local backup = http.formvalue("backup")
+       local reset  = reset_avail and http.formvalue("reset")
+       local backup_cmd  = "tar -cz %s 2>/dev/null"
        
-       http.header(
-               'Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' % {
-                       nixio.uname().nodename, os.date("%Y-%m-%d")
-               }
-       )
-       http.prepare_content("application/x-targz")
+       if http.formvalue("cancel") then
+               return http.redirect(dsp.build_url("niu"))
+       end
        
+       if backup then
+               local call = {"/bin/tar", "-cz"}
+               for k, v in pairs(uci:get_all("luci", "flash_keep")) do
+                       if k:byte() ~= 46 then  -- k[1] ~= "."
+                               nutl.consume(fs.glob(v), call)
+                       end
+               end
+               
+               
+               http.header(
+                       'Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' % {
+                               nixio.uname().nodename, os.date("%Y-%m-%d")
+                       }
+               )
+               http.prepare_content("application/x-targz")
+               
+               
+               local fdin, fdout = nixio.pipe()
+               local devnull = nixio.open("/dev/null", "r+")
+               local proc = nixio.fork()
+               
+               if proc == 0 then
+                       fdin:close()
+                       nixio.dup(devnull, nixio.stdin)
+                       nixio.dup(devnull, nixio.stderr)
+                       nixio.dup(fdout, nixio.stdout)
+                       nixio.exec(unpack(call))
+                       os.exit(1)
+               end
+               
+               fdout:close()
+               http.splice(fdin)
+               http.close()
+       elseif (upload and #upload > 0) or reset then
+               tpl.render("niu/system/reboot")
+               if nixio.fork() == 0 then
+                       nixio.nanosleep(1)
+                       if reset then
+                               nixio.execp("mtd", "-r", "erase", "rootfs_data")
+                       else
+                               nixio.execp("reboot")
+                       end
+                       os.exit(1)
+               end
+       else
+               tpl.render("niu/system/backup", {reset_avail = reset_avail})
+       end
+end
+
+function upgrade()
+       local io, os, table = require "io", require "os", require "table"
+       local uci = require "luci.store".uci_state
+       local http = require "luci.http"
+       local util = require "luci.util"
+       local tpl = require "luci.template"
+       local nixio = require "nixio", require "nixio.util", require "nixio.fs"
+
+
+       local tmpfile = "/tmp/firmware.img"
+       
+       local function image_supported()
+               -- XXX: yay...
+               return ( 0 == os.execute(
+                       ". /etc/functions.sh; " ..
+                       "include /lib/upgrade; " ..
+                       "platform_check_image %q >/dev/null"
+                               % tmpfile
+               ) )
+       end
        
-       local fdin, fdout = nixio.pipe()
-       local devnull = nixio.open("/dev/null", "r+")
-       local proc = nixio.fork()
+       local function image_checksum()
+               return (util.exec("md5sum %q" % tmpfile):match("^([^%s]+)"))
+       end
        
-       if proc == 0 then
-               fdin:close()
-               nixio.dup(devnull, nixio.stdin)
-               nixio.dup(devnull, nixio.stderr)
-               nixio.dup(fdout, nixio.stdout)
-               nixio.exec(unpack(call))
-               os.exit(1)
+       local function storage_size()
+               local size = 0
+               if nixio.fs.access("/proc/mtd") then
+                       for l in io.lines("/proc/mtd") do
+                               local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"')
+                               if n == "linux" then
+                                       size = tonumber(s, 16)
+                                       break
+                               end
+                       end
+               elseif nixio.fs.access("/proc/partitions") then
+                       for l in io.lines("/proc/partitions") do
+                               local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)')
+                               if b and n and not n:match('[0-9]') then
+                                       size = tonumber(b) * 1024
+                                       break
+                               end
+                       end
+               end
+               return size
        end
+
+
+       -- Install upload handler
+       local file
+       http.setfilehandler(
+               function(meta, chunk, eof)
+                       if not nixio.fs.access(tmpfile) and not file and chunk and #chunk > 0 then
+                               file = io.open(tmpfile, "w")
+                       end
+                       if file and chunk then
+                               file:write(chunk)
+                       end
+                       if file and eof then
+                               file:close()
+                       end
+               end
+       )
+
+
+       -- Determine state
+       local keep_avail   = true
+       local step         = tonumber(http.formvalue("step") or 1)
+       local has_image    = nixio.fs.access(tmpfile)
+       local has_support  = image_supported()
+       local has_platform = nixio.fs.access("/lib/upgrade/platform.sh")
+       local has_upload   = http.formvalue("image")
+       
+       -- This does the actual flashing which is invoked inside an iframe
+       -- so don't produce meaningful errors here because the the 
+       -- previous pages should arrange the stuff as required.
+       if step == 4 then
+               if has_platform and has_image and has_support then
+                       -- Mimetype text/plain
+                       http.prepare_content("text/plain")
+                       
+                       local call = {}
+                       for k, v in pairs(uci:get_all("luci", "flash_keep")) do
+                               if k:byte() ~= 46 then  -- k[1] ~= "."
+                                       nixio.util.consume(nixio.fs.glob(v), call)
+                               end
+                       end
+
+                       -- Now invoke sysupgrade
+                       local keepcfg = keep_avail and http.formvalue("keepcfg") == "1"
+                       local fd = io.popen("/sbin/luci-flash %s %q" %{
+                               keepcfg and "-k %q" % table.concat(call, " ") or "", tmpfile
+                       })
+
+                       if fd then
+                               while true do
+                                       local ln = fd:read("*l")
+                                       if not ln then break end
+                                       http.write(ln .. "\n")
+                               end
+                               fd:close()
+                       end
+
+                       -- Make sure the device is rebooted
+                       if nixio.fork() == 0 then
+                               nixio.nanosleep(1)
+                               nixio.execp("reboot")
+                               os.exit(1)
+                       end
+               end
+
+
+       --
+       -- This is step 1-3, which does the user interaction and
+       -- image upload.
+       --
+
+       -- Step 1: file upload, error on unsupported image format
+       elseif not has_image or not has_support or step == 1 then
+               -- If there is an image but user has requested step 1
+               -- or type is not supported, then remove it.
+               if has_image then
+                       nixio.fs.unlink(tmpfile)
+               end
+                       
+               tpl.render("niu/system/upgrade", {
+                       step=1,
+                       bad_image=(has_image and not has_support or false),
+                       keepavail=keep_avail,
+                       supported=has_platform
+               } )
+
+       -- Step 2: present uploaded file, show checksum, confirmation
+       elseif step == 2 then
+               tpl.render("niu/system/upgrade", {
+                       step=2,
+                       checksum=image_checksum(),
+                       filesize=nixio.fs.stat(tmpfile).size,
+                       flashsize=storage_size(),
+                       keepconfig=(keep_avail and http.formvalue("keepcfg") == "1")
+               } )
        
-       fdout:close()
-       http.splice(fdin)
-       http.close()
+       -- Step 3: load iframe which calls the actual flash procedure
+       elseif step == 3 then
+               tpl.render("niu/system/upgrade", {
+                       step=3,
+                       keepconfig=(keep_avail and http.formvalue("keepcfg") == "1")
+               } )
+       end     
 end
\ No newline at end of file
index b5d97d2b1c71cd4c3dc6f8d7ca51da7f72b1af98..6f6237e6080b7ca65913b44a3edc4ed7dbebd368 100644 (file)
@@ -1,10 +1,12 @@
-local cursor = require "luci.model.uci".cursor()
+local uci = require "luci.model.uci"
+local cursor = uci.cursor()
 local d = Delegator()
 d.allow_finish = true
 d.allow_back = true
 d.allow_cancel = true
 
 d:add("lan1", load("niu/network/lan1"))
+d:set("warnip", {Template("niu/network/warn_ip_change")})
 
 function d.on_cancel()
        cursor:revert("network")
@@ -12,6 +14,12 @@ function d.on_cancel()
 end
 
 function d.on_done()
+       if uci.inst_state:get("network", "lan", "ipaddr") ~= cursor:get("network", "lan", "ipaddr") then
+               local cs = uci.cursor_state()
+               cs:set("network", "lan", "_ipchanged", "1")
+               cs:save("network")
+       end
+
        cursor:commit("network")
        cursor:commit("dhcp")
 end
diff --git a/modules/niu/luasrc/model/cbi/niu/system/reboot.lua b/modules/niu/luasrc/model/cbi/niu/system/reboot.lua
new file mode 100644 (file)
index 0000000..d8f852b
--- /dev/null
@@ -0,0 +1 @@
+local f = Form("reboot", "Rebooting Device", "Device is rebooting. Please wait...") 
\ No newline at end of file
index a022b0af83fcad3ea9aaab51ee3d6af142b7dd57..86447123129a3ede87a377bc9b14816ad8c3d153 100644 (file)
@@ -1,13 +1,19 @@
 <%
 local dsp = require "luci.dispatcher"
 local utl = require "luci.util"
-local str = require "luci.store"
+local uci = require "luci.model.uci"
 
 local nws = {}
-str.uci_state:foreach("network", "interface", function(s)
+uci.inst_state:foreach("network", "interface", function(s)
        nws[#nws+1] = s
 end)
+
+if uci.inst_state:get("network", "lan", "_ipchanged") and
+uci.inst_state:revert("network", "lan", "_ipchanged") then
+       include("niu/network/warn_ip_change")
+end
 %>
+
 <div>Status:</div>
 <table>
 <% 
diff --git a/modules/niu/luasrc/view/niu/network/warn_ip_change.htm b/modules/niu/luasrc/view/niu/network/warn_ip_change.htm
new file mode 100644 (file)
index 0000000..b5ebdd7
--- /dev/null
@@ -0,0 +1,2 @@
+<strong>Warning!<br />
+Device IP has changed.</strong>
\ No newline at end of file
diff --git a/modules/niu/luasrc/view/niu/system/backup.htm b/modules/niu/luasrc/view/niu/system/backup.htm
new file mode 100644 (file)
index 0000000..7e8c728
--- /dev/null
@@ -0,0 +1,41 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
+-%>
+<%+header%>
+<h2><a id="content" name="content"><%:System%></a></h2>
+<h3><%:Backup / Restore%></h3>
+<p><%:Here you can backup and restore your router configuration and - if possible - reset the router to the default settings.%></p>
+<br />
+<div>
+       <ul>
+       <li><a href="<%=REQUEST_URI%>?backup=kthxbye"><%:Create backup%></a></li>
+       <% if reset_avail then -%>
+       <li><a href="<%=REQUEST_URI%>?reset=yarly" onclick="return confirm('<%:Proceed reverting all settings and resetting to firmware defaults?%>')"><%:Reset router to defaults%></a></li>
+       <% end -%>
+       </ul>
+</div>
+
+<br />
+
+<form method="post" action="<%=REQUEST_URI%>" enctype="multipart/form-data">
+       <div class="left"><%:Backup Archive%>:</div>
+       <div>
+               <input type="file" size="30" name="archive" />
+       </div>
+       <div>
+               <input type="submit" name="cancel" class="cbi-input-cancel" value="<%:Cancel%>" />
+               <input type="submit" class="cbi-input-apply" value="<%:Restore backup%>" />
+       </div>
+</form>
+<%+footer%>
\ No newline at end of file
diff --git a/modules/niu/luasrc/view/niu/system/reboot.htm b/modules/niu/luasrc/view/niu/system/reboot.htm
new file mode 100644 (file)
index 0000000..4b356d6
--- /dev/null
@@ -0,0 +1,14 @@
+Rebooting. Please wait...
+
+<script type="text/javascript">
+window.setInterval(function() {
+       var xmlHttp = new XMLHttpRequest();
+    xmlHttp.open('GET', '/', true);
+    xmlHttp.onreadystatechange = function () {
+        if (xmlHttp.readyState == 4 && req.status >= 200 && req.status < 400) {
+               window.location = "/";
+        }
+    };
+    xmlHttp.send(null);
+}, 10000);
+</script>
\ No newline at end of file
diff --git a/modules/niu/luasrc/view/niu/system/upgrade.htm b/modules/niu/luasrc/view/niu/system/upgrade.htm
new file mode 100644 (file)
index 0000000..1083a16
--- /dev/null
@@ -0,0 +1,105 @@
+<%#
+LuCI - Lua Configuration Interface
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008-2009 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+
+-%>
+
+<%+header%>
+
+<h2><a id="content" name="content"><%:System%></a></h2>
+<h3><%:Flash Firmware%></h3>
+
+<% if step == 1 then %>
+       <% if supported then %>
+       <form method="post" action="<%=REQUEST_URI%>" enctype="multipart/form-data">
+       <p>
+               <%:Upload an OpenWrt image file to reflash the device.%>
+               <% if bad_image then %>
+                       <br /><br />
+                       <div class="error"><%:The uploaded image file does not
+                               contain a supported format. Make sure that you choose the generic
+                               image format for your platform. %></div>
+               <% end %>
+       </p>
+       <div>
+               <%:Firmware image%>:<br />
+               <input type="hidden" name="step" value="2" />
+               <input type="file" size="30" name="image" />
+               <br />
+               <br />
+               <% if keepavail then -%>
+               <input type="checkbox" name="keepcfg" value="1" checked="checked" />
+               <span class="bold"><%:Keep configuration files%></span>
+               <% end -%>
+
+               <br />
+               <input class="cbi-button cbi-button-apply" type="submit" value="<%:Upload image%>" />
+       </div>
+       </form>
+       <% else %>
+               <div class="error"><%_ Sorry.
+                       OpenWrt does not support a system upgrade on this platform.<br />
+                       You need to manually flash your device. %></div>
+       <% end %>
+<% elseif step == 2 then %>
+       <p>
+               <%_ The flash image was uploaded.
+                       Below is the checksum and file size listed,
+                       compare them with the original file to ensure data integrity.<br />
+                       Click "Proceed" below to start the flash procedure. %>
+
+               <% if flashsize > 0 and filesize > flashsize then %>
+                       <br /><br />
+                       <div class="error"><%:It appears that you try to
+                               flash an image that does not fit into the flash memory, please verify
+                               the image file! %></div>
+               <% end %>
+
+               <br />
+               <ul>
+                       <li><%:Checksum%>: <code><%=checksum%></code></li>
+                       <li><%:Size%>: <%
+                               local w = require "luci.tools.webadmin"
+                               write(w.byte_format(filesize))
+       
+                               if flashsize > 0 then
+                                       write(luci.i18n.translatef(
+                                               " (%s available)",
+                                               w.byte_format(flashsize)
+                                       ))
+                               end
+                       %></li>
+               </ul>
+       </p>
+       <div class="cbi-page-actions right">
+               <form style="display:inline">
+                       <input type="hidden" name="step" value="3" />
+                       <input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>" />
+                       <input class="cbi-button cbi-button-apply" type="submit" value="<%:Proceed%>" />        
+               </form>
+               <form style="display:inline">
+                       <input type="hidden" name="step" value="1" />
+                       <input type="hidden" name="keepcfg" value="<%=keepconfig and "1" or "0"%>" />
+                       <input class="cbi-button cbi-button-reset" type="submit" value="<%:Cancel%>" />
+               </form>
+       </div>
+<% elseif step == 3 then %>
+       <p><%_ The system is flashing now.<br />
+               DO NOT POWER OFF THE DEVICE!<br />
+               Wait a few minutes until you try to reconnect.
+               It might be necessary to renew the address of your computer to reach the device
+               again, depending on your settings. %></p>
+               
+       <iframe src="<%=REQUEST_URI%>?step=4&#38;keepcfg=<%=keepconfig and "1" or "0"%>" style="border:1px solid black; width:100%; height:150px"></iframe>
+<% end %>
+<%+footer%>
+