luci-app-ddns: fix to correct system status
[project/luci.git] / applications / luci-app-ddns / luasrc / controller / ddns.lua
old mode 100644 (file)
new mode 100755 (executable)
index b11388c..1dfa625
@@ -1,18 +1,8 @@
---[[
-LuCI - Lua Configuration Interface
-
-Copyright 2008 Steven Barth <steven@midlink.org>
-Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
-Copyright 2014 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
-
-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$
-]]--
+-- Copyright 2008 Steven Barth <steven@midlink.org>
+-- Copyright 2008 Jo-Philipp Wich <jow@openwrt.org>
+-- Copyright 2013 Manuel Munz <freifunk at somakoma dot de>
+-- Copyright 2014-2017 Christian Schoenebeck <christian dot schoenebeck at gmail dot com>
+-- Licensed to the public under the Apache License 2.0.
 
 module("luci.controller.ddns", package.seeall)
 
@@ -20,51 +10,118 @@ local NX   = require "nixio"
 local NXFS = require "nixio.fs"
 local DISP = require "luci.dispatcher"
 local HTTP = require "luci.http"
-local UCI  = require "luci.model.uci"
+local I18N = require "luci.i18n"               -- not globally avalible here
+local IPKG = require "luci.model.ipkg"
 local SYS  = require "luci.sys"
-local DDNS = require "luci.tools.ddns"         -- ddns multiused functions
+local UCI  = require "luci.model.uci"
 local UTIL = require "luci.util"
+local DDNS = require "luci.tools.ddns"         -- ddns multiused functions
 
-local luci_ddns_version = "2.1.0-3"    -- luci-app-ddns / openwrt Makefile compatible version
-local ddns_scripts_min  = "2.1.0-2"    -- minimum version of ddns-scripts required
+luci_helper = "/usr/lib/ddns/dynamic_dns_lucihelper.sh"
+
+local srv_name    = "ddns-scripts"
+local srv_ver_min = "2.7.6"                    -- minimum version of service required
+local srv_ver_cmd = luci_helper .. [[ -V | awk {'print $2'}]]
+local app_name    = "luci-app-ddns"
+local app_title   = "Dynamic DNS"
+local app_version = "2.4.8-2"
 
 function index()
-       -- no services_ipv6 file or no dynamic_dns_lucihelper.sh
-       -- do NOT start
-       if not nixio.fs.access("/usr/lib/ddns/services_ipv6") 
-       or not nixio.fs.access("/usr/lib/ddns/dynamic_dns_lucihelper.sh") then
-               return
-       end
+       local nxfs      = require "nixio.fs"            -- global definitions not available
+       local sys       = require "luci.sys"            -- in function index()
+       local ddns      = require "luci.tools.ddns"     -- ddns multiused functions
+       local muci      = require "luci.model.uci"
+
        -- no config create an empty one
-       if not nixio.fs.access("/etc/config/ddns") then
-               nixio.fs.writefile("/etc/config/ddns", "")
+       if not nxfs.access("/etc/config/ddns") then
+               nxfs.writefile("/etc/config/ddns", "")
        end
 
+       -- preset new option "lookup_host" if not already defined
+       local uci = muci.cursor()
+       local commit = false
+       uci:foreach("ddns", "service", function (s)
+               if not s["lookup_host"] and s["domain"] then
+                       uci:set("ddns", s[".name"], "lookup_host", s["domain"])
+                       commit = true
+               end
+       end)
+       if commit then uci:commit("ddns") end
+       uci:unload("ddns")
+
        entry( {"admin", "services", "ddns"}, cbi("ddns/overview"), _("Dynamic DNS"), 59)
        entry( {"admin", "services", "ddns", "detail"}, cbi("ddns/detail"), nil ).leaf = true
        entry( {"admin", "services", "ddns", "hints"}, cbi("ddns/hints",
                {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), nil ).leaf = true
+       entry( {"admin", "services", "ddns", "global"}, cbi("ddns/global"), nil ).leaf = true
        entry( {"admin", "services", "ddns", "logview"}, call("logread") ).leaf = true
-       entry( {"admin", "services", "ddns", "startstop"}, call("startstop") ).leaf = true
+       entry( {"admin", "services", "ddns", "startstop"}, post("startstop") ).leaf = true
        entry( {"admin", "services", "ddns", "status"}, call("status") ).leaf = true
 end
 
--- function to read all sections status and return data array
+-- Application specific information functions
+function app_description()
+       return  I18N.translate("Dynamic DNS allows that your router can be reached with " ..
+                       "a fixed hostname while having a dynamically changing IP address.")
+               .. [[<br />]]
+               .. I18N.translate("OpenWrt Wiki") .. ": "
+               .. [[<a href="http://wiki.openwrt.org/doc/howto/ddns.client" target="_blank">]]
+               .. I18N.translate("DDNS Client Documentation") .. [[</a>]]
+               .. " --- "
+               .. [[<a href="http://wiki.openwrt.org/doc/uci/ddns" target="_blank">]]
+               .. I18N.translate("DDNS Client Configuration") .. [[</a>]]
+end
+function app_title_back()
+       return  [[<a href="]]
+               .. DISP.build_url("admin", "services", "ddns")
+               .. [[">]]
+               .. I18N.translate(app_title)
+               .. [[</a>]]
+end
+
+-- Standardized application/service functions
+function app_title_main()
+       return  [[<a href="javascript:alert(']]
+                       .. I18N.translate("Version Information")
+                       .. [[\n\n]] .. app_name
+                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]] .. app_version
+                       .. [[\n\n]] .. srv_name .. [[ ]] .. I18N.translate("required") .. [[:]]
+                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
+                               .. srv_ver_min .. [[ ]] .. I18N.translate("or higher")
+                       .. [[\n\n]] .. srv_name .. [[ ]] .. I18N.translate("installed") .. [[:]]
+                       .. [[\n\t]] .. I18N.translate("Version") .. [[:\t]]
+                               .. (service_version() or I18N.translate("NOT installed"))
+                       .. [[\n\n]]
+               .. [[')">]]
+               .. I18N.translate(app_title)
+               .. [[</a>]]
+end
+function service_version()
+       local ver = nil
+
+       ver = UTIL.exec(srv_ver_cmd)
+       if #ver > 0 then return ver end
+
+       IPKG.list_installed(srv_name, function(n, v, d)
+                       if v and (#v > 0) then ver = v end
+               end
+       )
+       return  ver
+end
+function service_ok()
+       return  IPKG.compare_versions((service_version() or "0"), ">=", srv_ver_min)
+end
+
+-- internal function to read all sections status and return data array
 local function _get_status()
        local uci        = UCI.cursor()
        local service    = SYS.init.enabled("ddns") and 1 or 0
        local url_start  = DISP.build_url("admin", "system", "startup")
-       local luci_build = DDNS.ipkg_version("luci-app-ddns").version
-       local ddns_act   = DDNS.ipkg_version("ddns-scripts").version
        local data       = {}   -- Array to transfer data to javascript
 
        data[#data+1]   = {
                enabled    = service,           -- service enabled
                url_up     = url_start,         -- link to enable DDS (System-Startup)
-               luci_ver   = luci_ddns_version, -- luci-app-ddns / openwrt Makefile compatible version
-               luci_build = luci_build,        -- installed luci build
-               script_min = ddns_scripts_min,  -- minimum version of ddns-scripts needed
-               script_ver = ddns_act           -- installed ddns-scripts
        }
 
        uci:foreach("ddns", "service", function (s)
@@ -73,8 +130,8 @@ local function _get_status()
                -- and enabled state
                local section   = s[".name"]
                local enabled   = tonumber(s["enabled"]) or 0
-               local datelast  = "_empty_"     -- formated date of last update
-               local datenext  = "_empty_"     -- formated date of next update
+               local datelast  = "_empty_"     -- formatted date of last update
+               local datenext  = "_empty_"     -- formatted date of next update
 
                -- get force seconds
                local force_seconds = DDNS.calc_seconds(
@@ -104,7 +161,7 @@ local function _get_status()
                end
 
                -- process running but update needs to happen
-               -- problems it force_seconds > uptime
+               -- problems if force_seconds > uptime
                force_seconds = (force_seconds > uptime) and uptime or force_seconds
                if pid > 0 and ( lasttime + force_seconds - uptime ) <= 0 then
                        datenext = "_verify_"
@@ -117,27 +174,31 @@ local function _get_status()
                elseif pid == 0 and enabled == 0 then
                        datenext  = "_disabled_"
 
-               -- no process running and NOT
+               -- no process running and enabled
                elseif pid == 0 and enabled ~= 0 then
                        datenext = "_stopped_"
                end
 
                -- get/set monitored interface and IP version
-               local iface     = s["interface"] or "_nonet_"
+               local iface     = s["interface"] or "wan"
                local use_ipv6  = tonumber(s["use_ipv6"]) or 0
-               if iface ~= "_nonet_" then
-                       local ipv = (use_ipv6 == 1) and "IPv6" or "IPv4"
-                       iface = ipv .. " / " .. iface
-               end
+               local ipv = (use_ipv6 == 1) and "IPv6" or "IPv4"
+               iface = ipv .. " / " .. iface
 
                -- try to get registered IP
-               local domain    = s["domain"] or "_nodomain_"
+               local lookup_host = s["lookup_host"] or "_nolookup_"
                local dnsserver = s["dns_server"] or ""
                local force_ipversion = tonumber(s["force_ipversion"] or 0)
                local force_dnstcp = tonumber(s["force_dnstcp"] or 0)
-               local command = [[/usr/lib/ddns/dynamic_dns_lucihelper.sh]]
-               command = command .. [[ get_registered_ip ]] .. domain .. [[ ]] .. use_ipv6 ..
-                       [[ ]] .. force_ipversion .. [[ ]] .. force_dnstcp .. [[ ]] .. dnsserver
+               local is_glue = tonumber(s["is_glue"] or 0)
+               local command = luci_helper .. [[ -]]
+               if (use_ipv6 == 1) then command = command .. [[6]] end
+               if (force_ipversion == 1) then command = command .. [[f]] end
+               if (force_dnstcp == 1) then command = command .. [[t]] end
+               if (is_glue == 1) then command = command .. [[g]] end
+               command = command .. [[l ]] .. lookup_host
+               if (#dnsserver > 0) then command = command .. [[ -d ]] .. dnsserver end
+               command = command .. [[ -- get_registered_ip]]
                local reg_ip = SYS.exec(command)
                if reg_ip == "" then
                        reg_ip = "_nodata_"
@@ -148,7 +209,7 @@ local function _get_status()
                        section  = section,
                        enabled  = enabled,
                        iface    = iface,
-                       domain   = domain,
+                       lookup   = lookup_host,
                        reg_ip   = reg_ip,
                        pid      = pid,
                        datelast = datelast,
@@ -163,11 +224,11 @@ end
 -- called by XHR.get from detail_logview.htm
 function logread(section)
        -- read application settings
-       local uci         = UCI.cursor()
-       local log_dir     = uci:get("ddns", "global", "log_dir") or "/var/log/ddns"
-       local lfile=log_dir .. "/" .. section .. ".log"
+       local uci       = UCI.cursor()
+       local ldir      = uci:get("ddns", "global", "ddns_logdir") or "/var/log/ddns"
+       local lfile     = ldir .. "/" .. section .. ".log"
+       local ldata     = NXFS.readfile(lfile)
 
-       local ldata=NXFS.readfile(lfile)
        if not ldata or #ldata == 0 then
                ldata="_nodata_"
        end
@@ -178,10 +239,10 @@ end
 -- called by XHR.get from overview_status.htm
 function startstop(section, enabled)
        local uci  = UCI.cursor()
+       local pid  = DDNS.get_pid(section)
        local data = {}         -- Array to transfer data to javascript
 
        -- if process running we want to stop and return
-       local pid = DDNS.get_pid(section)
        if pid > 0 then
                local tmp = NX.kill(pid, 15)    -- terminate
                NX.nanosleep(2) -- 2 second "show time"
@@ -192,7 +253,7 @@ function startstop(section, enabled)
                return
        end
 
-       -- read uncommited changes
+       -- read uncommitted changes
        -- we don't save and commit data from other section or other options
        -- only enabled will be done
        local exec        = true
@@ -220,9 +281,9 @@ function startstop(section, enabled)
        end
 
        -- we can not execute because other
-       -- uncommited changes pending, so exit here
+       -- uncommitted changes pending, so exit here
        if not exec then
-               HTTP.write("_uncommited_")
+               HTTP.write("_uncommitted_")
                return
        end
 
@@ -232,8 +293,9 @@ function startstop(section, enabled)
        uci:commit("ddns")
        uci:unload("ddns")
 
-       -- start dynamic_dns_updater.sh script
-       os.execute ([[/usr/lib/ddns/dynamic_dns_updater.sh %s 0 > /dev/null 2>&1 &]] % section)
+       -- start ddns-updater for section
+       local command = luci_helper .. [[ -S ]] .. section .. [[ -- start]]
+       os.execute(command)
        NX.nanosleep(3) -- 3 seconds "show time"
 
        -- status changed so return full status
@@ -249,13 +311,3 @@ function status()
        HTTP.write_json(data)
 end
 
--- check if installed ddns-scripts version < required version
-function update_needed()
-       local sver = DDNS.ipkg_version("ddns-scripts")
-       local rver = UTIL.split(ddns_scripts_min, "[%.%-]", nil, true)
-       return (sver.major < (tonumber(rver[1]) or 0))
-           or (sver.minor < (tonumber(rver[2]) or 0))
-           or (sver.patch < (tonumber(rver[3]) or 0))
-           or (sver.build < (tonumber(rver[4]) or 0))
-end
-