luci-app-ddns: whitespace fixes in overview.js
[project/luci.git] / applications / luci-app-ddns / htdocs / luci-static / resources / view / ddns / overview.js
1 'use strict';
2 'require ui';
3 'require view';
4 'require dom';
5 'require poll';
6 'require uci';
7 'require rpc';
8 'require fs';
9 'require form';
10 'require tools.widgets as widgets';
11
12 return view.extend({
13
14 NextUpdateStrings : {
15 'Verify' : _("Verify"),
16 'Run once' : _("Run once"),
17 'Disabled' : _("Disabled"),
18 'Stopped' : _("Stopped")
19 },
20
21 time_res : {
22 seconds : 1,
23 minutes : 60,
24 hours : 3600,
25 },
26
27 callGetLogServices: rpc.declare({
28 object: 'luci.ddns',
29 method: 'get_services_log',
30 params: [ 'service_name' ],
31 expect: { },
32 }),
33
34 callInitAction: rpc.declare({
35 object: 'luci',
36 method: 'setInitAction',
37 params: [ 'name', 'action' ],
38 expect: { result: false }
39 }),
40
41 callDDnsGetStatus: rpc.declare({
42 object: 'luci.ddns',
43 method: 'get_ddns_state',
44 expect: { }
45 }),
46
47 callDDnsGetEnv: rpc.declare({
48 object: 'luci.ddns',
49 method: 'get_env',
50 expect: { }
51 }),
52
53 callDDnsGetServicesStatus: rpc.declare({
54 object: 'luci.ddns',
55 method: 'get_services_status',
56 expect: { }
57 }),
58
59 services: {},
60
61 /*
62 * Services list is gen by 3 different source:
63 * 1. /usr/share/ddns/default contains the service installed by opkg
64 * 2. /usr/share/ddns/custom contains any service installed by the
65 * user or the ddns script (for example when service are
66 * downloaded)
67 * 3. /usr/share/ddns/list contains all the service that can be
68 * downloaded by using the ddns script ('service on demand' feature)
69 *
70 * (Special services that requires a dedicated package ARE NOT
71 * supported by the 'service on demand' feature)
72 */
73 callGenServiceList: function(m, ev) {
74 return Promise.all([
75 L.resolveDefault(fs.list('/usr/share/ddns/default'), []),
76 L.resolveDefault(fs.list('/usr/share/ddns/custom'), []),
77 L.resolveDefault(fs.read('/usr/share/ddns/list'), null)
78 ]).then(L.bind(function (data) {
79 var default_service = data[0],
80 custom_service = data[1],
81 list_service = data[2] && data[2].split("\n") || [],
82 _this = this;
83
84 this.services = {};
85
86 default_service.forEach(function (service) {
87 _this.services[service.name.replace('.json','')] = true
88 });
89
90 custom_service.forEach(function (service) {
91 _this.services[service.name.replace('.json','')] = true
92 });
93
94 list_service.forEach(function (service) {
95 if (!_this.services[service])
96 _this.services[service] = false;
97 });
98 }, this))
99 },
100
101 /*
102 * Check if the service is supported.
103 * If the script doesn't find any json assume a 'service on demand' install.
104 * If a json is found check if the ip type is supported.
105 * Invalidate the service_name if is not supported.
106 */
107 handleCheckService : function(s, service_name, ipv6, ev, section_id) {
108
109 var value = service_name.formvalue(section_id);
110 s.service_supported = null;
111 service_name.triggerValidation(section_id);
112
113 return this.handleGetServiceData(value)
114 .then(L.bind(function (service_data) {
115 if (value != '-' && service_data) {
116 service_data = JSON.parse(service_data);
117 if (ipv6.formvalue(section_id) == "1" && !service_data.ipv6) {
118 s.service_supported = false;
119 return;
120 }
121 }
122 s.service_supported = true;
123 }, service_name))
124 .then(L.bind(service_name.triggerValidation, service_name, section_id))
125 },
126
127 handleGetServiceData: function(service) {
128 return Promise.all([
129 L.resolveDefault(fs.read('/usr/share/ddns/custom/'+service+'.json'), null),
130 L.resolveDefault(fs.read('/usr/share/ddns/default/'+service+'.json'), null)
131 ]).then(function(data) {
132 return data[0] || data[1] || null;
133 })
134 },
135
136 handleInstallService: function(m, service_name, section_id, section, _this, ev) {
137 var service = service_name.formvalue(section_id)
138 return fs.exec('/usr/bin/ddns', ['service', 'install', service])
139 .then(L.bind(_this.callGenServiceList, _this))
140 .then(L.bind(m.render, m))
141 .then(L.bind(this.renderMoreOptionsModal, this, section))
142 .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
143 },
144
145 handleRefreshServicesList: function(m, ev) {
146 return fs.exec('/usr/bin/ddns', ['service', 'update'])
147 .then(L.bind(this.load, this))
148 .then(L.bind(this.render, this))
149 .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
150 },
151
152 handleReloadDDnsRule: function(m, section_id, ev) {
153 return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
154 [ '-S', section_id, '--', 'start' ])
155 .then(L.bind(m.load, m))
156 .then(L.bind(m.render, m))
157 .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
158 },
159
160 HandleStopDDnsRule: function(m, section_id, ev) {
161 return fs.exec('/usr/lib/ddns/dynamic_dns_lucihelper.sh',
162 [ '-S', section_id, '--', 'start' ])
163 .then(L.bind(m.render, m))
164 .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
165 },
166
167 handleToggleDDns: function(m, ev) {
168 return this.callInitAction('ddns', 'enabled')
169 .then(L.bind(function (action) { return this.callInitAction('ddns', action ? 'disable' : 'enable')}, this))
170 .then(L.bind(function (action) { return this.callInitAction('ddns', action ? 'stop' : 'start')}, this))
171 .then(L.bind(m.render, m))
172 .catch(function(e) { ui.addNotification(null, E('p', e.message)) });
173 },
174
175 handleRestartDDns: function(m, ev) {
176 return this.callInitAction('ddns', 'restart')
177 .then(L.bind(m.render, m));
178 },
179
180 poll_status: function(map, data) {
181 var status = data[1] || [], service = data[0] || [], rows = map.querySelectorAll('.cbi-section-table-row[data-sid]'),
182 section_id, cfg_detail_ip, cfg_update, cfg_status, host, ip, last_update,
183 next_update, service_status, reload, cfg_enabled, stop,
184 ddns_enabled = map.querySelector('[data-name="_enabled"]').querySelector('.cbi-value-field'),
185 ddns_toggle = map.querySelector('[data-name="_toggle"]').querySelector('button'),
186 services_list = map.querySelector('[data-name="_services_list"]').querySelector('.cbi-value-field');
187
188 ddns_toggle.innerHTML = status['_enabled'] ? _('Stop DDNS') : _('Start DDNS')
189 services_list.innerHTML = status['_services_list'];
190
191 dom.content(ddns_enabled, function() {
192 return E([], [
193 E('div', {}, status['_enabled'] ? _('DDNS Autostart enabled') : [
194 _('DDNS Autostart disabled'),
195 E('div', { 'class' : 'cbi-value-description' },
196 _("Currently DDNS updates are not started at boot or on interface events.") + "<br />" +
197 _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')"))
198 ]),]);
199 });
200
201 for (var i = 0; i < rows.length; i++) {
202 section_id = rows[i].getAttribute('data-sid');
203 cfg_detail_ip = rows[i].querySelector('[data-name="_cfg_detail_ip"]');
204 cfg_update = rows[i].querySelector('[data-name="_cfg_update"]');
205 cfg_status = rows[i].querySelector('[data-name="_cfg_status"]');
206 reload = rows[i].querySelector('.cbi-section-actions .reload');
207 stop = rows[i].querySelector('.cbi-section-actions .stop');
208 cfg_enabled = uci.get('ddns', section_id, 'enabled');
209
210 reload.disabled = (status['_enabled'] == 0 || cfg_enabled == 0);
211
212 host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error');
213 ip = _('No Data');
214 last_update = _('Never');
215 next_update = _('Unknown');
216 service_status = '<b>' + _('Not Running') + '</b>';
217
218 if (service[section_id]) {
219 stop.disabled = (!service[section_id].pid || (service[section_id].pid && cfg_enabled == '1'));
220 if (service[section_id].ip)
221 ip = service[section_id].ip;
222 if (service[section_id].last_update)
223 last_update = service[section_id].last_update;
224 if (service[section_id].next_update)
225 next_update = this.NextUpdateStrings[service[section_id].next_update] || service[section_id].next_update;
226 if (service[section_id].pid)
227 service_status = '<b>' + _('Running') + '</b> : ' + service[section_id].pid;
228 }
229
230 cfg_detail_ip.innerHTML = host + '<br />' + ip;
231 cfg_update.innerHTML = last_update + '<br />' + next_update;
232 cfg_status.innerHTML = service_status;
233 }
234
235 return;
236 },
237
238 load: function() {
239 return Promise.all([
240 this.callDDnsGetServicesStatus(),
241 this.callDDnsGetStatus(),
242 this.callDDnsGetEnv(),
243 this.callGenServiceList(),
244 uci.load('ddns')
245 ]);
246 },
247
248 render: function(data) {
249 var resolved = data[0] || [];
250 var status = data[1] || [];
251 var env = data[2] || [];
252 var logdir = uci.get('ddns', 'global', 'ddns_logdir') || "/var/log/ddns";
253
254 var _this = this;
255
256 var m, s, o;
257
258 m = new form.Map('ddns', _('Dynamic DNS'));
259
260 s = m.section(form.NamedSection, 'global', 'ddns',);
261
262 s.tab('info', _('Information'));
263 s.tab('global', _('Global Settings'));
264
265 o = s.taboption('info', form.DummyValue, '_version', _('Dynamic DNS Version'));
266 o.cfgvalue = function() {
267 return status[this.option];
268 };
269
270 o = s.taboption('info', form.DummyValue, '_enabled', _('State'));
271 o.cfgvalue = function() {
272 var res = status[this.option];
273 if (!res) {
274 this.description = _("Currently DDNS updates are not started at boot or on interface events.") + "<br />" +
275 _("This is the default if you run DDNS scripts by yourself (i.e. via cron with force_interval set to '0')")
276 }
277 return res ? _('DDNS Autostart enabled') : _('DDNS Autostart disabled')
278 };
279
280 o = s.taboption('info', form.Button, '_toggle');
281 o.title = '&#160;';
282 o.inputtitle = _((status['_enabled'] ? 'stop' : 'start').toUpperCase() + ' DDns');
283 o.inputstyle = 'apply';
284 o.onclick = L.bind(this.handleToggleDDns, this, m);
285
286 o = s.taboption('info', form.Button, '_restart');
287 o.title = '&#160;';
288 o.inputtitle = _('Restart DDns');
289 o.inputstyle = 'apply';
290 o.onclick = L.bind(this.handleRestartDDns, this, m);
291
292 o = s.taboption('info', form.DummyValue, '_services_list', _('Services list last update'));
293 o.cfgvalue = function() {
294 return status[this.option];
295 };
296
297 o = s.taboption('info', form.Button, '_refresh_services');
298 o.title = '&#160;';
299 o.inputtitle = _('Update DDns Services List');
300 o.inputstyle = 'apply';
301 o.onclick = L.bind(this.handleRefreshServicesList, this, m);
302
303 // DDns hints
304
305 if (!env['has_ipv6']) {
306 o = s.taboption('info', form.DummyValue, '_no_ipv6');
307 o.rawhtml = true;
308 o.title = '<b>' + _("IPv6 not supported") + '</b>';
309 o.cfgvalue = function() { return _("IPv6 is currently not (fully) supported by this system") + "<br />" +
310 _("Please follow the instructions on OpenWrt's homepage to enable IPv6 support") + "<br />" +
311 _("or update your system to the latest OpenWrt Release")};
312 }
313
314 if (!env['has_ssl']) {
315 o = s.taboption('info', form.DummyValue, '_no_https');
316 o.titleref = L.url("admin", "system", "opkg")
317 o.rawhtml = true;
318 o.title = '<b>' + _("HTTPS not supported") + '</b>';
319 o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to support secure updates via HTTPS protocol.") +
320 "<br />- " +
321 _("You should install 'wget' or 'curl' or 'uclient-fetch' with 'libustream-*ssl' package.") +
322 "<br />- " +
323 _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
324 }
325
326 if (!env['has_bindnet']) {
327 o = s.taboption('info', form.DummyValue, '_no_bind_network');
328 o.titleref = L.url("admin", "system", "opkg")
329 o.rawhtml = true;
330 o.title = '<b>' + _("Binding to a specific network not supported") + '</b>';
331 o.cfgvalue = function() { return _("Neither GNU Wget with SSL nor cURL installed to select a network to use for communication.") +
332 "<br />- " +
333 _("You should install 'wget' or 'curl' package.") +
334 "<br />- " +
335 _("GNU Wget will use the IP of given network, cURL will use the physical interface.") +
336 "<br />- " +
337 _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
338 }
339
340 if (!env['has_proxy']) {
341 o = s.taboption('info', form.DummyValue, '_no_proxy');
342 o.titleref = L.url("admin", "system", "opkg")
343 o.rawhtml = true;
344 o.title = '<b>' + _("cURL without Proxy Support") + '</b>';
345 o.cfgvalue = function() { return _("cURL is installed, but libcurl was compiled without proxy support.") +
346 "<br />- " +
347 _("You should install 'wget' or 'uclient-fetch' package or replace libcurl.") +
348 "<br />- " +
349 _("In some versions cURL/libcurl in OpenWrt is compiled without proxy support.")};
350 }
351
352 if (!env['has_forceip']) {
353 o = s.taboption('info', form.DummyValue, '_no_force_ip');
354 o.titleref = L.url("admin", "system", "opkg")
355 o.rawhtml = true;
356 o.title = '<b>' + _("Force IP Version not supported") + '</b>';
357 o.cfgvalue = function() { return _("BusyBox's nslookup and Wget do not support to specify " +
358 "the IP version to use for communication with DDNS Provider!") +
359 "<br />- " + _("You should install 'wget' or 'curl' or 'uclient-fetch' package.")
360 };
361 }
362
363 if (!env['has_bindhost']) {
364 o = s.taboption('info', form.DummyValue, '_no_dnstcp');
365 o.titleref = L.url("admin", "system", "opkg")
366 o.rawhtml = true;
367 o.title = '<b>' + _("DNS requests via TCP not supported") + '</b>';
368 o.cfgvalue = function() { return _("BusyBox's nslookup and hostip do not support to specify to use TCP " +
369 "instead of default UDP when requesting DNS server!") +
370 "<br />- " +
371 _("You should install 'bind-host' or 'knot-host' or 'drill' package for DNS requests.")};
372 }
373
374 if (!env['has_dnsserver']) {
375 o = s.taboption('info', form.DummyValue, '_no_dnsserver');
376 o.titleref = L.url("admin", "system", "opkg")
377 o.rawhtml = true;
378 o.title = '<b>' + _("Using specific DNS Server not supported") + '</b>';
379 o.cfgvalue = function() { return _("BusyBox's nslookup in the current compiled version " +
380 "does not handle given DNS Servers correctly!") +
381 "<br />- " +
382 _("You should install 'bind-host' or 'knot-host' or 'drill' or 'hostip' package, " +
383 "if you need to specify a DNS server to detect your registered IP.")};
384 }
385
386 if (env['has_ssl'] && !env['has_cacerts']) {
387 o = s.taboption('info', form.DummyValue, '_no_certs');
388 o.titleref = L.url("admin", "system", "opkg")
389 o.rawhtml = true;
390 o.title = '<b>' + _("No certificates found") + '</b>';
391 o.cfgvalue = function() { return _("If using secure communication you should verify server certificates!") +
392 "<br />- " +
393 _("Install 'ca-certificates' package or needed certificates " +
394 "by hand into /etc/ssl/certs default directory")};
395 }
396
397 // Advanced Configuration Section
398
399 o = s.taboption('global', form.Flag, 'upd_privateip', _("Allow non-public IP's"));
400 o.description = _("Non-public and by default blocked IP's") + ':'
401 + '<br /><strong>IPv4: </strong>'
402 + '0/8, 10/8, 100.64/10, 127/8, 169.254/16, 172.16/12, 192.168/16'
403 + '<br /><strong>IPv6: </strong>'
404 + '::/32, f000::/4"';
405 o.default = "0";
406 o.optional = true;
407
408 o = s.taboption('global', form.Value, 'ddns_dateformat', _('Date format'));
409 o.description = '<a href="http://www.cplusplus.com/reference/ctime/strftime/" target="_blank">'
410 + _("For supported codes look here")
411 + '</a><br />' +
412 _('Current setting: ') + '<b>' + status['_curr_dateformat'] + '</b>';
413 o.default = "%F %R"
414 o.optional = true;
415 o.rmempty = true;
416
417 o = s.taboption('global', form.Value, 'ddns_rundir', _('Status directory'));
418 o.description = _('Directory contains PID and other status information for each running section.');
419 o.default = "/var/run/ddns";
420 o.optional = true;
421 o.rmempty = true;
422
423 o = s.taboption('global', form.Value, 'ddns_logdir', _('Log directory'));
424 o.description = _('Directory contains Log files for each running section.');
425 o.default = "/var/log/ddns";
426 o.optional = true;
427 o.rmempty = true;
428 o.validate = function(section_id, formvalue) {
429 if (formvalue.indexOf('../') !== -1)
430 return _('"../" not allowed in path for Security Reason.')
431
432 return true;
433 }
434
435 o = s.taboption('global', form.Value, 'ddns_loglines', _('Log length'));
436 o.description = _('Number of last lines stored in log files');
437 o.datatype = 'min(1)';
438 o.default = '250';
439
440 if (env['has_wget'] && env['has_curl']) {
441
442 o = s.taboption('global', form.Flag, 'use_curl', _('Use cURL'));
443 o.description = _('If Wget and cURL package are installed, Wget is used for communication by default.');
444 o.default = "0";
445 o.optional = true;
446 o.rmempty = true;
447
448 }
449
450 o = s.taboption('global', form.Value, 'cacert', _('Ca Certs path'));
451 o.description = _('Ca Certs path that will be used to download services data. Set IGNORE to skip certificate validation.');
452 o.placeholder = 'IGNORE';
453
454 o = s.taboption('global', form.Value, 'services_url', _('Services URL Download'));
455 o.description = _('Url used to download services file. By default is the master openwrt ddns package repo.');
456 o.placeholder = 'https://raw.githubusercontent.com/openwrt/packages/master/net/ddns-scripts/files';
457
458 // DDns services
459 s = m.section(form.GridSection, 'service', _('Services'));
460 s.anonymous = true;
461 s.addremove = true;
462 s.addbtntitle = _('Add new services...');
463
464 s.anonymous = true;
465 s.addremove = true;
466 s.sortable = true;
467
468 s.handleCreateDDnsRule = function(m, name, service_name, ipv6, ev) {
469 var section_id = name.isValid('_new_') ? name.formvalue('_new_') : null,
470 service_value = service_name.isValid('_new_') ? service_name.formvalue('_new_') : null,
471 ipv6_value = ipv6.isValid('_new_') ? ipv6.formvalue('_new_') : null;
472
473 if (section_id == null || section_id == '' || service_value == null || section_id == '' || ipv6_value == null || ipv6_value == '')
474 return;
475
476 return m.save(function() {
477 uci.add('ddns', 'service', section_id);
478 uci.set('ddns', section_id, 'service_name', service_value);
479 uci.set('ddns', section_id, 'use_ipv6', ipv6_value);
480 }).then(L.bind(m.children[1].renderMoreOptionsModal, m.children[1], section_id));
481 };
482
483 s.handleAdd = function(ev) {
484 var m2 = new form.Map('ddns'),
485 s2 = m2.section(form.NamedSection, '_new_'),
486 name, ipv6, service_name;
487
488 s2.render = function() {
489 return Promise.all([
490 {},
491 this.renderUCISection('_new_')
492 ]).then(this.renderContents.bind(this));
493 };
494
495 name = s2.option(form.Value, 'name', _('Name'));
496 name.rmempty = false;
497 name.datatype = 'uciname';
498 name.placeholder = _('New DDns Service…');
499 name.validate = function(section_id, value) {
500 if (uci.get('ddns', value) != null)
501 return _('The service name is already used');
502
503 return true;
504 };
505
506 ipv6 = s2.option( form.ListValue, 'use_ipv6',
507 _("IP address version"),
508 _("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider"));
509 ipv6.default = '0';
510 ipv6.value("0", _("IPv4-Address"))
511 if (env["has_ipv6"]) {
512 ipv6.value("1", _("IPv6-Address"))
513 }
514
515 service_name = s2.option(form.ListValue, 'service_name',
516 String.format('%s', _("DDNS Service provider")));
517 service_name.value('-',"-- " + _("custom") + " --");
518 for (var elem in _this.services)
519 service_name.value(elem);
520 service_name.validate = function(section_id, value) {
521 if (value == '') return _("Select a service");
522 if (s2.service_supported == null) return _("Checking the service support...");
523 if (!s2.service_supported) return _("Service doesn't support this ip type");
524 return true;
525 };
526
527 ipv6.onchange = L.bind(_this.handleCheckService, _this, s2, service_name, ipv6);
528 service_name.onchange = L.bind(_this.handleCheckService, _this, s2, service_name, ipv6);
529
530 m2.render().then(L.bind(function(nodes) {
531 ui.showModal(_('Add new services...'), [
532 nodes,
533 E('div', { 'class': 'right' }, [
534 E('button', {
535 'class': 'btn',
536 'click': ui.hideModal
537 }, _('Cancel')), ' ',
538 E('button', {
539 'class': 'cbi-button cbi-button-positive important',
540 'click': ui.createHandlerFn(this, 'handleCreateDDnsRule', m, name, service_name, ipv6)
541 }, _('Create service'))
542 ])
543 ], 'cbi-modal');
544
545 nodes.querySelector('[id="%s"] input[type="text"]'.format(name.cbid('_new_'))).focus();
546 }, this));
547 };
548
549 s.renderRowActions = function(section_id) {
550 var tdEl = this.super('renderRowActions', [ section_id, _('Edit') ]),
551 cfg_enabled = uci.get('ddns', section_id, 'enabled'),
552 reload_opt = {
553 'class': 'cbi-button cbi-button-neutral reload',
554 'click': ui.createHandlerFn(_this, 'handleReloadDDnsRule', m, section_id),
555 'title': _('Reload this service'),
556 },
557 stop_opt = {
558 'class': 'cbi-button cbi-button-neutral stop',
559 'click': ui.createHandlerFn(_this, 'HandleStopDDnsRule', m, section_id),
560 'title': _('Stop this service'),
561 };
562
563 if (status['_enabled'] == 0 || cfg_enabled == 0)
564 reload_opt['disabled'] = 'disabled';
565
566 if (!resolved[section_id] || !resolved[section_id].pid ||
567 (resolved[section_id].pid && cfg_enabled == '1'))
568 stop_opt['disabled'] = 'disabled';
569
570 dom.content(tdEl.lastChild, [
571 E('button', stop_opt, _('Stop')),
572 E('button', reload_opt, _('Reload')),
573 tdEl.lastChild.childNodes[0],
574 tdEl.lastChild.childNodes[1],
575 tdEl.lastChild.childNodes[2]
576 ]);
577
578 return tdEl;
579 };
580
581 s.modaltitle = function(section_id) {
582 return _('DDns Service') + ' » ' + section_id;
583 };
584
585 s.addModalOptions = function(s, section_id) {
586
587 var service = uci.get('ddns', section_id, 'service_name') || '-',
588 ipv6 = uci.get('ddns', section_id, 'use_ipv6'), service_name, use_ipv6;
589
590 return _this.handleGetServiceData(service).then(L.bind(function (service_data) {
591 s.service_available = true;
592 s.service_supported = true;
593
594 if (service != '-') {
595 if (!service_data)
596 s.service_available = false;
597 else {
598 service_data = JSON.parse(service_data);
599 if (ipv6 == "1" && !service_data.ipv6)
600 s.service_supported = false;
601 }
602 }
603
604 s.tab('basic', _('Basic Settings'));
605 s.tab('advanced', _('Advanced Settings'));
606 s.tab('timer', _('Timer Settings'));
607 s.tab('logview', _('Log File Viewer'));
608
609 o = s.taboption('basic', form.Flag, 'enabled',
610 _('Enabled'),
611 _("If this service section is disabled it could not be started.")
612 + "<br />" +
613 _("Neither from LuCI interface nor from console."));
614 o.modalonly = true;
615 o.rmempty = false;
616 o.default = '1';
617
618 o = s.taboption('basic', form.Value, 'lookup_host',
619 _("Lookup Hostname"),
620 _("Hostname/FQDN to validate, if IP update happen or necessary"));
621 o.rmempty = false;
622 o.placeholder = "myhost.example.com";
623 o.datatype = 'and(minlength(3),hostname("strict"))';
624 o.modalonly = true;
625
626 use_ipv6 = s.taboption('basic', form.ListValue, 'use_ipv6',
627 _("IP address version"),
628 _("Defines which IP address 'IPv4/IPv6' is send to the DDNS provider"));
629 use_ipv6.default = '0';
630 use_ipv6.modalonly = true;
631 use_ipv6.rmempty = false;
632 use_ipv6.value("0", _("IPv4-Address"))
633 if (env["has_ipv6"]) {
634 use_ipv6.value("1", _("IPv6-Address"))
635 }
636
637 service_name = s.taboption('basic', form.ListValue, 'service_name',
638 String.format('%s', _("DDNS Service provider")));
639 service_name.modalonly = true;
640 service_name.value('-',"-- " + _("custom") + " --");
641 for (var elem in _this.services)
642 service_name.value(elem);
643 service_name.cfgvalue = function(section_id) {
644 return uci.get('ddns', section_id, 'service_name') || '-';
645 };
646 service_name.write = function(section_id, service) {
647 if (service != '-') {
648 uci.set('ddns', section_id, 'update_url', null);
649 uci.set('ddns', section_id, 'update_script', null);
650 return uci.set('ddns', section_id, 'service_name', service);
651 }
652 return uci.set('ddns', section_id, 'service_name', null);
653 };
654 service_name.validate = function(section_id, value) {
655 if (value == '') return _("Select a service");
656 if (s.service_available == null) return _("Checking the service support...");
657 if (!s.service_available) return _('Service not installed');
658 if (!s.service_supported) return _("Service doesn't support this ip type");
659 return true;
660 };
661
662 service_name.onchange = L.bind(_this.handleCheckService, _this, s, service_name, use_ipv6);
663 use_ipv6.onchange = L.bind(_this.handleCheckService, _this, s, service_name, use_ipv6);
664
665 if (!s.service_available) {
666 o = s.taboption('basic', form.Button, '_download_service');
667 o.modalonly = true;
668 o.title = _('Service not installed');
669 o.inputtitle = _('Install Service');
670 o.inputstyle = 'apply';
671 o.onclick = L.bind(_this.handleInstallService,
672 this, m, service_name, section_id, s.section, _this)
673 }
674
675 if (!s.service_supported) {
676 o = s.taboption('basic', form.DummyValue, '_not_supported', '&nbsp');
677 o.cfgvalue = function () {
678 return _("Service doesn't support this ip type")
679 };
680 }
681
682 var service_switch = s.taboption('basic', form.Button, '_switch_proto');
683 service_switch.modalonly = true;
684 service_switch.title = _('Really switch service?');
685 service_switch.inputtitle = _('Switch service');
686 service_switch.inputstyle = 'apply';
687 service_switch.onclick = L.bind(function(ev) {
688 if (!s.service_supported) return;
689
690 return s.map.save()
691 .then(L.bind(m.load, m))
692 .then(L.bind(m.render, m))
693 .then(L.bind(this.renderMoreOptionsModal, this, s.section));
694 }, this);
695
696 if (s.service_available && s.service_supported) {
697
698 o = s.taboption('basic', form.Value, 'update_url',
699 _("Custom update-URL"),
700 _("Update URL to be used for updating your DDNS Provider.")
701 + "<br />" +
702 _("Follow instructions you will find on their WEB page."));
703 o.modalonly = true;
704 o.rmempty = true;
705 o.optional = true;
706 o.depends("service_name","-");
707 o.validate = function(section_id, value) {
708 var other = this.section.children.filter(function(o) { return o.option == 'update_script' })[0].formvalue(section_id);
709
710 if ((value == "" && other == "") || (value != "" && other != "")) {
711 return _("Insert a Update Script OR a Update URL");
712 }
713
714 return true;
715 };
716
717 o = s.taboption('basic', form.Value, 'update_script',
718 _("Custom update-script"),
719 _("Custom update script to be used for updating your DDNS Provider."));
720 o.modalonly = true;
721 o.rmempty = true;
722 o.optional = true;
723 o.depends("service_name","-");
724 o.validate = function(section_id, value) {
725 var other = this.section.children.filter(function(o) { return o.option == 'update_url' })[0].formvalue(section_id);
726
727 if ((value == "" && other == "") || (value != "" && other != "")) {
728 return _("Insert a Update Script OR a Update URL");
729 }
730
731 return true;
732 };
733
734 o = s.taboption('basic', form.Value, 'domain',
735 _("Domain"),
736 _("Replaces [USERNAME] in Update-URL (URL-encoded)"));
737 o.modalonly = true;
738 o.rmempty = false;
739
740 o = s.taboption('basic', form.Value, 'username',
741 _("Username"),
742 _("Replaces [USERNAME] in Update-URL (URL-encoded)"));
743 o.modalonly = true;
744 o.rmempty = false;
745
746 o = s.taboption('basic', form.Value, 'password',
747 _("Password"),
748 _("Replaces [PASSWORD] in Update-URL (URL-encoded)"));
749 o.password = true;
750 o.modalonly = true;
751 o.rmempty = false;
752
753 o = s.taboption('basic', form.Value, 'param_enc',
754 _("Optional Encoded Parameter"),
755 _("Optional: Replaces [PARAMENC] in Update-URL (URL-encoded)"));
756 o.optional = true;
757 o.modalonly = true;
758
759 o = s.taboption('basic', form.Value, 'param_opt',
760 _("Optional Parameter"),
761 _("Optional: Replaces [PARAMOPT] in Update-URL (NOT URL-encoded)"));
762 o.optional = true;
763 o.modalonly = true;
764
765 if (env['has_ssl']) {
766 o = s.taboption('basic', form.Flag, 'use_https',
767 _("Use HTTP Secure"),
768 _("Enable secure communication with DDNS provider"));
769 o.optional = true;
770 o.modalonly = true;
771
772 o = s.taboption('basic', form.Value, 'cacert',
773 _("Path to CA-Certificate"),
774 _("directory or path/file")
775 + "<br />" +
776 _("or")
777 + '<b>' + " IGNORE " + '</b>' +
778 _("to run HTTPS without verification of server certificates (insecure)"));
779 o.modalonly = true;
780 o.depends("use_https", "1");
781 o.placeholder = "/etc/ssl/certs";
782 o.rmempty = false;
783 };
784
785
786 o = s.taboption('advanced', form.ListValue, 'ip_source',
787 _("IP address source"),
788 _("Defines the source to read systems IP-Address from, that will be send to the DDNS provider"));
789 o.modalonly = true;
790 o.default = "network";
791 o.value("network", _("Network"));
792 o.value("web", _("URL"));
793 o.value("interface", _("Interface"));
794 o.value("script", _("Script"));
795 o.write = function(section_id, formvalue) {
796 switch(formvalue) {
797 case 'network':
798 uci.set('ddns', section_id, "ip_url",null);
799 uci.set('ddns', section_id, "ip_interface",null);
800 uci.set('ddns', section_id, "ip_script",null);
801 break;
802 case 'web':
803 uci.set('ddns', section_id, "ip_network",null);
804 uci.set('ddns', section_id, "ip_interface",null);
805 uci.set('ddns', section_id, "ip_script",null);
806 break;
807 case 'interface':
808 uci.set('ddns', section_id, "ip_network",null);
809 uci.set('ddns', section_id, "ip_url",null);
810 uci.set('ddns', section_id, "ip_script",null);
811 break;
812 case 'script':
813 uci.set('ddns', section_id, "ip_network",null);
814 uci.set('ddns', section_id, "ip_url",null);
815 uci.set('ddns', section_id, "ip_interface",null);
816 break;
817 default:
818 break;
819 };
820
821 return uci.set('ddns', section_id, 'ip_source', formvalue )
822 };
823
824 o = s.taboption('advanced', widgets.NetworkSelect, 'ip_network',
825 _("Network"),
826 _("Defines the network to read systems IP-Address from"));
827 o.depends('ip_source','network');
828 o.modalonly = true;
829 o.default = 'wan';
830 o.multiple = false;
831
832 o = s.taboption('advanced', form.Value, 'ip_url',
833 _("URL to detect"),
834 _("Defines the Web page to read systems IP-Address from.")
835 + '<br />' +
836 String.format('%s %s', _('Example for IPv4'), ': http://checkip.dyndns.com')
837 + '<br />' +
838 String.format('%s %s', _('Example for IPv6'), ': http://checkipv6.dyndns.com'));
839 o.depends("ip_source", "web")
840 o.modalonly = true;
841
842 o = s.taboption('advanced', widgets.DeviceSelect, 'ip_interface',
843 _("Interface"),
844 _("Defines the interface to read systems IP-Address from"));
845 o.modalonly = true;
846 o.depends("ip_source", "interface")
847 o.multiple = false;
848 o.default = 'wan';
849
850 o = s.taboption('advanced', form.Value, 'ip_script',
851 _("Script"),
852 _("User defined script to read systems IP-Address"));
853 o.modalonly = true;
854 o.depends("ip_source", "script")
855 o.placeholder = "/path/to/script.sh"
856
857 o = s.taboption('advanced', widgets.DeviceSelect, 'interface',
858 _("Event Network"),
859 _("Network on which the ddns-updater scripts will be started"));
860 o.modalonly = true;
861 o.multiple = false;
862 o.default = 'wan';
863 o.depends("ip_source", "web");
864 o.depends("ip_source", "script");
865
866 o = s.taboption('advanced', form.DummyValue, '_interface',
867 _("Event Network"),
868 _("Network on which the ddns-updater scripts will be started"));
869 o.depends("ip_source", "interface");
870 o.depends("ip_source", "network");
871 o.forcewrite = true;
872 o.modalonly = true;
873 o.cfgvalue = function(section_id) {
874 return uci.get('ddns', section_id, 'interface') || _('This will be autoset to the selected interface');
875 };
876 o.write = function(section_id) {
877 var opt = this.section.children.filter(function(o) { return o.option == 'ip_source' })[0].formvalue(section_id);
878 var val = this.section.children.filter(function(o) { return o.option == 'ip_'+opt })[0].formvalue(section_id);
879 return uci.set('ddns', section_id, 'interface', val);
880 };
881
882 if (env['has_bindnet']) {
883 o = s.taboption('advanced', widgets.ZoneSelect, 'bind_network',
884 _("Bind Network"),
885 _('OPTIONAL: Network to use for communication')
886 + '<br />' +
887 _("Network on which the ddns-updater scripts will be started"));
888 o.depends("ip_source", "web");
889 o.optional = true;
890 o.rmempty = true;
891 o.modalonly = true;
892 }
893
894 if (env['has_forceip']) {
895 o = s.taboption('advanced', form.Flag, 'force_ipversion',
896 _("Force IP Version"),
897 _('OPTIONAL: Force the usage of pure IPv4/IPv6 only communication.'));
898 o.optional = true;
899 o.rmempty = true;
900 o.modalonly = true;
901 }
902
903 if (env['has_dnsserver']) {
904 o = s.taboption("advanced", form.Value, "dns_server",
905 _("DNS-Server"),
906 _("OPTIONAL: Use non-default DNS-Server to detect 'Registered IP'.")
907 + "<br />" +
908 _("Format: IP or FQDN"));
909 o.placeholder = "mydns.lan"
910 o.optional = true;
911 o.rmempty = true;
912 o.modalonly = true;
913 }
914
915 if (env['has_bindhost']) {
916 o = s.taboption("advanced", form.Flag, "force_dnstcp",
917 _("Force TCP on DNS"),
918 _("OPTIONAL: Force the use of TCP instead of default UDP on DNS requests."));
919 o.optional = true;
920 o.rmempty = true;
921 o.modalonly = true;
922 }
923
924 if (env['has_proxy']) {
925 o = s.taboption("advanced", form.Value, "proxy",
926 _("PROXY-Server"),
927 _("OPTIONAL: Proxy-Server for detection and updates.")
928 + "<br />" +
929 String.format('%s: <b>%s</b>', _("Format"), "[user:password@]proxyhost:port")
930 + "<br />" +
931 String.format('%s: <b>%s</b>', _("IPv6 address must be given in square brackets"), "[2001:db8::1]:8080"));
932 o.optional = true;
933 o.rmempty = true;
934 o.modalonly = true;
935 }
936
937 o = s.taboption("advanced", form.ListValue, "use_syslog",
938 _("Log to syslog"),
939 _("Writes log messages to syslog. Critical Errors will always be written to syslog."));
940 o.modalonly = true;
941 o.default = "2"
942 o.optional = true;
943 o.value("0", _("No logging"))
944 o.value("1", _("Info"))
945 o.value("2", _("Notice"))
946 o.value("3", _("Warning"))
947 o.value("4", _("Error"))
948
949 o = s.taboption("advanced", form.Flag, "use_logfile",
950 _("Log to file"));
951 o.default = '1';
952 o.optional = true;
953 o.modalonly = true;
954 o.cfgvalue = function(section_id) {
955 this.description = _("Writes detailed messages to log file. File will be truncated automatically.") + "<br />" +
956 _("File") + ': "' + logdir + '/' + section_id + '.log"';
957 return uci.get('ddns', section_id, 'use_logfile');
958 };
959
960
961 o = s.taboption("timer", form.Value, "check_interval",
962 _("Check Interval"));
963 o.placeholder = "30";
964 o.modalonly = true;
965 o.datatype = 'uinteger';
966 o.validate = function(section_id, formvalue) {
967 var unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
968 time_to_sec = _this.time_res[unit || 'minutes'] * formvalue;
969
970 if (formvalue && time_to_sec < 300)
971 return _('Values below 5 minutes == 300 seconds are not supported');
972
973 return true;
974 };
975
976 o = s.taboption("timer", form.ListValue, "check_unit",
977 _('Check Unit'),
978 _("Interval unit to check for changed IP"));
979 o.modalonly = true;
980 o.default = "minutes"
981 o.value("seconds", _("seconds"));
982 o.value("minutes", _("minutes"));
983 o.value("hours", _("hours"));
984
985 o = s.taboption("timer", form.Value, "force_interval",
986 _("Force Interval"),
987 _("Interval to force updates send to DDNS Provider")
988 + "<br />" +
989 _("Setting this parameter to 0 will force the script to only run once"));
990 o.placeholder = "72";
991 o.optional = true;
992 o.modalonly = true;
993 o.datatype = 'uinteger';
994 o.validate = function(section_id, formvalue) {
995
996 if (!formvalue)
997 return true;
998
999 var check_unit = this.section.children.filter(function(o) { return o.option == 'check_unit' })[0].formvalue(section_id),
1000 check_val = this.section.children.filter(function(o) { return o.option == 'check_interval' })[0].formvalue(section_id),
1001 force_unit = this.section.children.filter(function(o) { return o.option == 'force_unit' })[0].formvalue(section_id),
1002 check_to_sec = _this.time_res[check_unit || 'minutes'] * ( check_val || '30'),
1003 force_to_sec = _this.time_res[force_unit || 'minutes'] * formvalue;
1004
1005 if (force_to_sec != 0 && force_to_sec < check_to_sec)
1006 return _("Values lower 'Check Interval' except '0' are not supported");
1007
1008 return true;
1009 };
1010
1011 o = s.taboption("timer", form.ListValue, "force_unit",
1012 _('Force Unit'),
1013 _("Interval unit to force updates send to DDNS Provider"));
1014 o.modalonly = true;
1015 o.optional = true;
1016 o.default = "minutes"
1017 o.value("minutes", _("minutes"));
1018 o.value("hours", _("hours"));
1019 o.value("days", _("days"));
1020
1021 o = s.taboption("timer", form.Value, "retry_count",
1022 _("Error Retry Counter"),
1023 _("On Error the script will stop execution after given number of retrys")
1024 + "<br />" +
1025 _("The default setting of '0' will retry infinite."));
1026 o.placeholder = "0";
1027 o.optional = true;
1028 o.modalonly = true;
1029 o.datatype = 'uinteger';
1030
1031 o = s.taboption("timer", form.Value, "retry_interval",
1032 _("Error Retry Interval"),
1033 _("On Error the script will stop execution after given number of retrys")
1034 + "<br />" +
1035 _("The default setting of '0' will retry infinite."));
1036 o.placeholder = "60";
1037 o.optional = true;
1038 o.modalonly = true;
1039 o.datatype = 'uinteger';
1040
1041 o = s.taboption("timer", form.ListValue, "retry_unit",
1042 _('Retry Unit'),
1043 _("On Error the script will retry the failed action after given time"));
1044 o.modalonly = true;
1045 o.optional = true;
1046 o.default = "seconds"
1047 o.value("seconds", _("seconds"));
1048 o.value("minutes", _("minutes"));
1049
1050 o = s.taboption('logview', form.Button, '_read_log');
1051 o.title = '';
1052 o.depends('use_logfile','1');
1053 o.modalonly = true;
1054 o.inputtitle = _('Read / Reread log file');
1055 o.inputstyle = 'apply';
1056 o.onclick = L.bind(function(ev, section_id) {
1057 return _this.callGetLogServices(section_id).then(L.bind(log_box.update_log, log_box));
1058 }, this);
1059
1060 var log_box = s.taboption("logview", form.DummyValue, "_logview");
1061 log_box.depends('use_logfile','1');
1062 log_box.modalonly = true;
1063
1064 log_box.update_log = L.bind(function(view, log_data) {
1065 return document.getElementById('log_area').textContent = log_data.result;
1066 }, o, this);
1067
1068 log_box.render = L.bind(function() {
1069 return E([
1070 E('p', {}, _('This is the current content of the log file in ') + logdir + ' for this service.'),
1071 E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 20, 'readonly' : 'readonly', 'id' : 'log_area' }, _('Please press [Read] button') ))
1072 ]);
1073 }, o, this);
1074 }
1075
1076 for (var i = 0; i < s.children.length; i++) {
1077 o = s.children[i];
1078 switch (o.option) {
1079 case '_switch_proto':
1080 o.depends({ service_name : service, use_ipv6: ipv6, "!reverse": true })
1081 continue;
1082 case 'enabled':
1083 case 'service_name':
1084 case 'use_ipv6':
1085 case 'update_script':
1086 case 'update_url':
1087 case 'lookup_host':
1088 continue;
1089
1090 default:
1091 if (o.deps.length)
1092 for (var j = 0; j < o.deps.length; j++) {
1093 o.deps[j].service_name = service;
1094 o.deps[j].use_ipv6 = ipv6;
1095 }
1096 else
1097 o.depends({service_name: service, use_ipv6: ipv6 });
1098 }
1099 }
1100 }, this)
1101 )};
1102
1103 o = s.option(form.DummyValue, '_cfg_status', _('Status'));
1104 o.modalonly = false;
1105 o.textvalue = function(section_id) {
1106 var text = '<b>' + _('Not Running') + '</b>';
1107
1108 if (resolved[section_id] && resolved[section_id].pid)
1109 text = '<b>' + _('Running') + '</b> : ' + resolved[section_id].pid;
1110
1111 return text;
1112 };
1113
1114 o = s.option(form.DummyValue, '_cfg_name', _('Name'));
1115 o.modalonly = false;
1116 o.textvalue = function(section_id) {
1117 return '<b>' + section_id + '</b>';
1118 };
1119
1120 o = s.option(form.DummyValue, '_cfg_detail_ip', _('Lookup Hostname') + "<br />" + _('Registered IP'));
1121 o.rawhtml = true;
1122 o.modalonly = false;
1123 o.textvalue = function(section_id) {
1124 var host = uci.get('ddns', section_id, 'lookup_host') || _('Configuration Error'),
1125 ip = _('No Data');
1126 if (resolved[section_id] && resolved[section_id].ip)
1127 ip = resolved[section_id].ip;
1128
1129 return host + '<br />' + ip;
1130 };
1131
1132 o = s.option(form.Flag, 'enabled', _('Enabled'));
1133 o.rmempty = false;
1134 o.editable = true;
1135 o.modalonly = false;
1136
1137 o = s.option(form.DummyValue, '_cfg_update', _('Last Update') + "<br />" + _('Next Update'));
1138 o.rawhtml = true;
1139 o.modalonly = false;
1140 o.textvalue = function(section_id) {
1141 var last_update = _('Never'), next_update = _('Unknown');
1142 if (resolved[section_id]) {
1143 if (resolved[section_id].last_update)
1144 last_update = resolved[section_id].last_update;
1145 if (resolved[section_id].next_update)
1146 next_update = _this.NextUpdateStrings[resolved[section_id].next_update] || resolved[section_id].next_update;
1147 }
1148
1149 return last_update + '<br />' + next_update;
1150 };
1151
1152 return m.render().then(L.bind(function(m, nodes) {
1153 poll.add(L.bind(function() {
1154 return Promise.all([
1155 this.callDDnsGetServicesStatus(),
1156 this.callDDnsGetStatus()
1157 ]).then(L.bind(this.poll_status, this, nodes));
1158 }, this), 5);
1159 return nodes;
1160 }, this, m));
1161 }
1162 });