rs232

tomato.js

Feb 2nd, 2022 (edited)
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 70.53 KB | None | 0 0
  1. /*
  2. Tomato GUI
  3. Copyright (C) 2006-2010 Jonathan Zarate
  4. http://www.polarcloud.com/tomato/
  5.  
  6. For use with Tomato Firmware only.
  7. No part of this file may be used without permission.
  8. */
  9.  
  10. // -----------------------------------------------------------------------------
  11.  
  12. /* global variables */
  13. var MAX_BRIDGE_ID = 3;
  14. var MAX_PORT_ID = 4;
  15. var MAX_VLAN_ID = 15;
  16. /* DUALWAN-BEGIN */
  17. var xifs = [['wan', 'lan', 'lan1', 'lan2', 'lan3', 'wan2'],['WAN0', 'LAN0', 'LAN1', 'LAN2', 'LAN3', 'WAN1']];
  18. /* DUALWAN-END */
  19. /* MULTIWAN-BEGIN */
  20. var xifs = [['wan', 'lan', 'lan1', 'lan2', 'lan3', 'wan2', 'wan3', 'wan4'],['WAN0', 'LAN0', 'LAN1', 'LAN2', 'LAN3', 'WAN1', 'WAN2', 'WAN3']];
  21. /* MULTIWAN-END */
  22. var mac_null = '00:00:00:00:00:00';
  23. var serviceLastUp = [];
  24. var countButton = 0;
  25.  
  26. // -----------------------------------------------------------------------------
  27.  
  28. Array.prototype.find = function(v) {
  29. for (var i = 0; i < this.length; ++i)
  30. if (this[i] == v) return i;
  31. return -1;
  32. }
  33.  
  34. Array.prototype.remove = function(v) {
  35. for (var i = 0; i < this.length; ++i) {
  36. if (this[i] == v) {
  37. this.splice(i, 1);
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43.  
  44. // -----------------------------------------------------------------------------
  45.  
  46. String.prototype.trim = function() {
  47. return this.replace(/^\s+/, '').replace(/\s+$/, '');
  48. }
  49.  
  50. // -----------------------------------------------------------------------------
  51.  
  52. Number.prototype.pad = function(min) {
  53. var s = this.toString();
  54. while (s.length < min) s = '0' + s;
  55. return s;
  56. }
  57.  
  58. Number.prototype.hex = function(min) {
  59. var h = '0123456789ABCDEF';
  60. var n = this;
  61. var s = '';
  62. do {
  63. s = h.charAt(n & 15) + s;
  64. n = n >>> 4;
  65. } while ((--min > 0) || (n > 0));
  66. return s;
  67. }
  68.  
  69. // -----------------------------------------------------------------------------
  70.  
  71. // ---- Element.protoype. doesn't work with all browsers
  72.  
  73. var elem = {
  74. getOffset: function(e) {
  75. var r = { x: 0, y: 0 };
  76. e = E(e);
  77. while (e.offsetParent) {
  78. r.x += e.offsetLeft;
  79. r.y += e.offsetTop;
  80. e = e.offsetParent;
  81. }
  82. return r;
  83. },
  84.  
  85. addClass: function(e, name) {
  86. if ((e = E(e)) == null) return;
  87. var a = e.className.split(/\s+/);
  88. var k = 0;
  89. for (var i = 1; i < arguments.length; ++i) {
  90. if (a.find(arguments[i]) == -1) {
  91. a.push(arguments[i]);
  92. k = 1;
  93. }
  94. }
  95. if (k) e.className = a.join(' ');
  96. },
  97.  
  98. removeClass: function(e, name) {
  99. if ((e = E(e)) == null) return;
  100. var a = e.className.split(/\s+/);
  101. var k = 0;
  102. for (var i = 1; i < arguments.length; ++i)
  103. k |= a.remove(arguments[i]);
  104. if (k) e.className = a.join(' ');
  105. },
  106.  
  107. remove: function(e) {
  108. if ((e = E(e)) != null) e.parentNode.removeChild(e);
  109. },
  110.  
  111. parentElem: function(e, tagName) {
  112. e = E(e);
  113. tagName = tagName.toUpperCase();
  114. while (e.parentNode) {
  115. e = e.parentNode;
  116. if (e.tagName == tagName) return e;
  117. }
  118. return null;
  119. },
  120.  
  121. display: function() {
  122. var enable = arguments[arguments.length - 1];
  123. for (var i = 0; i < arguments.length - 1; ++i) {
  124. E(arguments[i]).style.display = (enable ? '' : 'none');
  125. }
  126. },
  127.  
  128. isVisible: function(e) {
  129. e = E(e);
  130. while (e) {
  131. if (e.style.display == 'none') return false;;
  132. e = e.parentNode;
  133. }
  134. return true;
  135. },
  136.  
  137. setInnerHTML: function(e, html) {
  138. e = E(e);
  139. if (e.innerHTML != html) e.innerHTML = html; /* reduce flickering */
  140. }
  141. };
  142.  
  143. // -----------------------------------------------------------------------------
  144.  
  145. var fields = {
  146. getAll: function(e) {
  147. var a = [];
  148. switch (e.tagName) {
  149. case 'INPUT':
  150. case 'SELECT':
  151. a.push(e);
  152. break;
  153. default:
  154. if (e.childNodes) {
  155. for (var i = 0; i < e.childNodes.length; ++i) {
  156. a = a.concat(fields.getAll(e.childNodes[i]));
  157. }
  158. }
  159. }
  160. return a;
  161. },
  162. disableAll: function(e, d) {
  163. var i;
  164.  
  165. if ((typeof(e.tagName) == 'undefined') && (typeof(e) != 'string')) {
  166. for (i = e.length - 1; i >= 0; --i) {
  167. e[i].disabled = d;
  168. }
  169. }
  170. else {
  171. var a = this.getAll(E(e));
  172. for (var i = a.length - 1; i >= 0; --i) {
  173. a[i].disabled = d;
  174. }
  175. }
  176. },
  177. radio: {
  178. selected: function(e) {
  179. for (var i = 0; i < e.length; ++i) {
  180. if (e[i].checked) return e[i];
  181. }
  182. return null;
  183. },
  184. find: function(e, value) {
  185. for (var i = 0; i < e.length; ++i) {
  186. if (e[i].value == value) return e[i];
  187. }
  188. return null;
  189. }
  190. }
  191. };
  192.  
  193. // -----------------------------------------------------------------------------
  194.  
  195. var form = {
  196. submitHidden: function(url, fields) {
  197. var fom, body;
  198.  
  199. fom = document.createElement('FORM');
  200. fom.action = url;
  201. fom.method = 'post';
  202. for (var f in fields) {
  203. var e = document.createElement('INPUT');
  204. e.type = 'hidden';
  205. e.name = f;
  206. e.value = fields[f];
  207. fom.appendChild(e);
  208. }
  209. body = document.getElementsByTagName('body')[0];
  210. fom = body.appendChild(fom);
  211. this.submit(fom);
  212. body.removeChild(fom);
  213. },
  214.  
  215. submit: function(fom, async, url) {
  216. var e, v, f, i, wait, msg, sb, cb, nomsg = 0;
  217.  
  218. fom = E(fom);
  219.  
  220. if (isLocal()) {
  221. this.dump(fom, async, url);
  222. return;
  223. }
  224.  
  225. if (this.xhttp) return;
  226.  
  227. if ((sb = E('save-button')) != null) sb.disabled = 1;
  228. if ((cb = E('cancel-button')) != null) cb.disabled = 1;
  229.  
  230. if ((!async) || (!useAjax())) {
  231. this.addId(fom);
  232. if (url) fom.action = url;
  233. fom.submit();
  234. return;
  235. }
  236.  
  237. v = ['_ajax=1'];
  238. wait = 5;
  239. for (var i = 0; i < fom.elements.length; ++i) {
  240. f = fom.elements[i];
  241. if ((f.disabled) || (f.name == '') || (f.name.substr(0, 2) == 'f_')) continue;
  242. if ((f.tagName == 'INPUT') && ((f.type == 'CHECKBOX') || (f.type == 'RADIO')) && (!f.checked)) continue;
  243. if (f.name == '_nextwait') {
  244. wait = f.value * 1;
  245. if (isNaN(wait))
  246. wait = 5;
  247. else
  248. wait = Math.abs(wait);
  249. }
  250. if (f.name == '_nofootermsg') {
  251. nomsg = f.value * 1;
  252. if (isNaN(nomsg))
  253. nomsg = 0;
  254. }
  255. v.push(escapeCGI(f.name) + '=' + escapeCGI(f.value));
  256. }
  257.  
  258. if ((msg = E('footer-msg')) != null && !nomsg) {
  259. msg.innerHTML = 'Saving...';
  260. msg.style.display = 'inline';
  261. }
  262.  
  263. this.xhttp = new XmlHttp();
  264. this.xhttp.onCompleted = function(text, xml) {
  265. if (msg && !nomsg) {
  266. if (text.match(/@msg:(.+)/))
  267. msg.innerHTML = escapeHTML(RegExp.$1);
  268. else
  269. msg.innerHTML = 'Saved';
  270. }
  271. setTimeout(
  272. function() {
  273. if (sb) sb.disabled = 0;
  274. if (cb) cb.disabled = 0;
  275. if (msg) msg.style.display = 'none';
  276. if (typeof(submit_complete) != 'undefined') submit_complete();
  277. }, wait * 1100);
  278. form.xhttp = null;
  279. }
  280. this.xhttp.onError = function(x) {
  281. if (url) fom.action = url;
  282. fom.submit();
  283. }
  284.  
  285. this.xhttp.post(url ? url : fom.action, v.join('&'));
  286. },
  287.  
  288. addId: function(fom) {
  289. var e;
  290.  
  291. if (typeof(fom._http_id) == 'undefined') {
  292. e = document.createElement('INPUT');
  293. e.type = 'hidden';
  294. e.name = '_http_id';
  295. e.value = nvram.http_id;
  296. fom.appendChild(e);
  297. }
  298. else {
  299. fom._http_id.value = nvram.http_id;
  300. }
  301. },
  302.  
  303. addIdAction: function(fom) {
  304. if (fom.action.indexOf('?') != -1)
  305. fom.action += '&_http_id=' + nvram.http_id;
  306. else
  307. fom.action += '?_http_id=' + nvram.http_id;
  308. },
  309.  
  310. dump: function(fom, async, url) {
  311. }
  312. };
  313.  
  314. // -----------------------------------------------------------------------------
  315.  
  316. var ferror = {
  317. set: function(e, message, quiet) {
  318. if ((e = E(e)) == null) return;
  319. e._error_msg = message;
  320. e._error_org = e.title;
  321. e.title = message;
  322. elem.addClass(e, 'error');
  323. if (!quiet) this.show(e);
  324. },
  325.  
  326. clear: function(e) {
  327. if ((e = E(e)) == null) return;
  328. e.title = e._error_org || '';
  329. elem.removeClass(e, 'error');
  330. e._error_msg = null;
  331. e._error_org = null;
  332. },
  333.  
  334. clearAll: function(e) {
  335. for (var i = 0; i < e.length; ++i)
  336. this.clear(e[i]);
  337. },
  338.  
  339. show: function(e) {
  340. if ((e = E(e)) == null) return;
  341. if (!e._error_msg) return;
  342. elem.addClass(e, 'error-focused');
  343. e.focus();
  344. alert(e._error_msg);
  345. elem.removeClass(e, 'error-focused');
  346. },
  347.  
  348. ok: function(e) {
  349. if ((e = E(e)) == null) return 0;
  350. return !e._error_msg;
  351. }
  352. };
  353.  
  354. // -----------------------------------------------------------------------------
  355.  
  356. function fixFile(name) {
  357. var i;
  358. if (((i = name.lastIndexOf('/')) > 0) || ((i = name.lastIndexOf('\\')) > 0))
  359. name = name.substring(i + 1, name.length);
  360. return name;
  361. }
  362.  
  363. function _v_range(e, quiet, min, max, name) {
  364. if ((e = E(e)) == null) return 0;
  365. var v = e.value;
  366. if ((!v.match(/^ *[-\+]?\d+ *$/)) || (v < min) || (v > max)) {
  367. ferror.set(e, 'Invalid ' + name + '. Valid range: ' + min + '-' + max, quiet);
  368. return 0;
  369. }
  370. e.value = v * 1;
  371. ferror.clear(e);
  372. return 1;
  373. }
  374.  
  375. function v_range(e, quiet, min, max) {
  376. return _v_range(e, quiet, min, max, 'number');
  377. }
  378.  
  379. function v_port(e, quiet) {
  380. return _v_range(e, quiet, 1, 0xFFFF, 'port');
  381. }
  382.  
  383. function v_octet(e, quiet) {
  384. return _v_range(e, quiet, 1, 254, 'address');
  385. }
  386.  
  387. function v_mins(e, quiet, min, max) {
  388. var v, m;
  389.  
  390. if ((e = E(e)) == null) return 0;
  391. if (e.value.match(/^\s*(.+?)([mhd])?\s*$/)) {
  392. m = 1;
  393. if (RegExp.$2 == 'h')
  394. m = 60;
  395. else if (RegExp.$2 == 'd')
  396. m = 60 * 24;
  397.  
  398. v = Math.round(RegExp.$1 * m);
  399. if (!isNaN(v)) {
  400. e.value = v;
  401. return _v_range(e, quiet, min, max, 'minutes');
  402. }
  403. }
  404. ferror.set(e, 'Invalid number of minutes.', quiet);
  405. return 0;
  406. }
  407.  
  408. function v_macip(e, quiet, bok, lan_ipaddr, lan_netmask) {
  409. var s, a, b, c, d, i;
  410. var ipp, temp;
  411.  
  412. temp = lan_ipaddr.split('.');
  413. ipp = temp[0]+'.'+temp[1]+'.'+temp[2]+'.';
  414.  
  415. if ((e = E(e)) == null) return 0;
  416. s = e.value.replace(/\s+/g, '');
  417.  
  418. if ((a = fixMAC(s)) != null) {
  419. if (isMAC0(a)) {
  420. if (bok) {
  421. e.value = '';
  422. }
  423. else {
  424. ferror.set(e, 'Invalid MAC or IP address');
  425. return false;
  426. }
  427. }
  428. else
  429. e.value = a;
  430.  
  431. ferror.clear(e);
  432. return true;
  433. }
  434.  
  435. a = s.split('-');
  436.  
  437. if (a.length > 2) {
  438. ferror.set(e, 'Invalid IP address range', quiet);
  439. return false;
  440. }
  441.  
  442. if (a[0].match(/^\d+$/)){
  443. a[0]=ipp+a[0];
  444. if ((a.length == 2) && (a[1].match(/^\d+$/)))
  445. a[1]=ipp+a[1];
  446. }
  447. else {
  448. if ((a.length == 2) && (a[1].match(/^\d+$/))){
  449. temp=a[0].split('.');
  450. a[1]=temp[0]+'.'+temp[1]+'.'+temp[2]+'.'+a[1];
  451. }
  452. }
  453. for (i = 0; i < a.length; ++i) {
  454. b = a[i];
  455. b = fixIP(b);
  456. if (!b) {
  457. ferror.set(e, 'Invalid IP address', quiet);
  458. return false;
  459. }
  460.  
  461. if ((aton(b) & aton(lan_netmask))!=(aton(lan_ipaddr) & aton(lan_netmask))) {
  462. ferror.set(e, 'IP address outside of LAN', quiet);
  463. return false;
  464. }
  465.  
  466. d = (b.split('.'))[3];
  467. if (parseInt(d) <= parseInt(c)) {
  468. ferror.set(e, 'Invalid IP address range', quiet);
  469. return false;
  470. }
  471.  
  472. a[i] = c = d;
  473. }
  474. e.value = b.split('.')[0] + '.' + b.split('.')[1] + '.' + b.split('.')[2] + '.' + a.join('-');
  475. return true;
  476. }
  477.  
  478. function fixIP(ip, x) {
  479. var a, n, i;
  480. a = ip;
  481. i = a.indexOf("<br>");
  482. if (i > 0)
  483. a = a.slice(0,i);
  484.  
  485. a = a.split('.');
  486. if (a.length != 4) return null;
  487. for (i = 0; i < 4; ++i) {
  488. n = a[i] * 1;
  489. if ((isNaN(n)) || (n < 0) || (n > 255)) return null;
  490. a[i] = n;
  491. }
  492. if ((x) && ((a[3] == 0) || (a[3] == 255))) return null;
  493. return a.join('.');
  494. }
  495.  
  496. function v_ip(e, quiet, x) {
  497. var ip;
  498.  
  499. if ((e = E(e)) == null) return 0;
  500. ip = fixIP(e.value, x);
  501. if (!ip) {
  502. ferror.set(e, 'Invalid IP address', quiet);
  503. return false;
  504. }
  505. e.value = ip;
  506. ferror.clear(e);
  507. return true;
  508. }
  509.  
  510. function v_ipz(e, quiet) {
  511. if ((e = E(e)) == null) return 0;
  512. if (e.value == '') e.value = '0.0.0.0';
  513. return v_ip(e, quiet);
  514. }
  515.  
  516. function v_dns(e, quiet) {
  517. if ((e = E(e)) == null) return 0;
  518. if (e.value == '') {
  519. e.value = '0.0.0.0';
  520. }
  521. else {
  522. var s = e.value.split(':');
  523. if (s.length == 1) {
  524. s.push(53);
  525. }
  526. else if (s.length != 2) {
  527. ferror.set(e, 'Invalid IP address or port', quiet);
  528. return false;
  529. }
  530.  
  531. if ((s[0] = fixIP(s[0])) == null) {
  532. ferror.set(e, 'Invalid IP address', quiet);
  533. return false;
  534. }
  535.  
  536. if ((s[1] = fixPort(s[1], -1)) == -1) {
  537. ferror.set(e, 'Invalid port', quiet);
  538. return false;
  539. }
  540.  
  541. if (s[1] == 53) {
  542. e.value = s[0];
  543. }
  544. else {
  545. e.value = s.join(':');
  546. }
  547. }
  548.  
  549. ferror.clear(e);
  550. return true;
  551. }
  552.  
  553. function aton(ip) {
  554. var o, x, i;
  555.  
  556. // ---- this is goofy because << mangles numbers as signed
  557. o = ip.split('.');
  558. x = '';
  559. for (i = 0; i < 4; ++i) x += (o[i] * 1).hex(2);
  560. return parseInt(x, 16);
  561. }
  562.  
  563. function ntoa(ip) {
  564. return ((ip >> 24) & 255) + '.' + ((ip >> 16) & 255) + '.' + ((ip >> 8) & 255) + '.' + (ip & 255);
  565. }
  566.  
  567. // ---- 1.2.3.4, 1.2.3.4/24, 1.2.3.4/255.255.255.0, 1.2.3.4-1.2.3.5
  568. function _v_iptip(e, ip, quiet) {
  569. var ma, x, y, z, oip;
  570. var a, b;
  571.  
  572. oip = ip;
  573.  
  574. /* x.x.x.x - y.y.y.y */
  575. if (ip.match(/^(.*)-(.*)$/)) {
  576. a = fixIP(RegExp.$1);
  577. b = fixIP(RegExp.$2);
  578. if ((a == null) || (b == null)) {
  579. ferror.set(e, oip + ' - invalid IP address range', quiet);
  580. return null;
  581. }
  582. ferror.clear(e);
  583.  
  584. if (aton(a) > aton(b)) return b + '-' + a;
  585. return a + '-' + b;
  586. }
  587.  
  588. ma = '';
  589.  
  590. /* x.x.x.x/nn */
  591. /* x.x.x.x/y.y.y.y */
  592. if (ip.match(/^(.*)\/(.*)$/)) {
  593. ip = RegExp.$1;
  594. b = RegExp.$2;
  595.  
  596. ma = b * 1;
  597. if (isNaN(ma)) {
  598. ma = fixIP(b);
  599. if ((ma == null) || (!_v_netmask(ma))) {
  600. ferror.set(e, oip + ' - invalid netmask', quiet);
  601. return null;
  602. }
  603. }
  604. else {
  605. if ((ma < 0) || (ma > 32)) {
  606. ferror.set(e, oip + ' - invalid netmask', quiet);
  607. return null;
  608. }
  609. }
  610. }
  611.  
  612. ip = fixIP(ip);
  613. if (!ip) {
  614. ferror.set(e, oip + ' - invalid IP address', quiet);
  615. return null;
  616. }
  617.  
  618. ferror.clear(e);
  619. return ip + ((ma != '') ? ('/' + ma) : '');
  620. }
  621.  
  622. function v_iptip(e, quiet, multi) {
  623. var v, i;
  624.  
  625. if ((e = E(e)) == null) return 0;
  626. v = e.value.split(',');
  627. if (multi) {
  628. if (v.length > multi) {
  629. ferror.set(e, 'Too many IP addresses', quiet);
  630. return 0;
  631. }
  632. }
  633. else {
  634. if (v.length > 1) {
  635. ferror.set(e, 'Invalid IP address', quiet);
  636. return 0;
  637. }
  638. }
  639. for (i = 0; i < v.length; ++i) {
  640. if ((v[i] = _v_iptip(e, v[i], quiet)) == null) return 0;
  641. }
  642. e.value = v.join(', ');
  643. return 1;
  644. }
  645.  
  646. function _v_subnet(e, ip, quiet) {
  647. var ma, oip;
  648. oip = ip;
  649.  
  650. /* x.x.x.x/nn */
  651. if (ip.match(/^(.*)\/(.*)$/)) {
  652. ip = RegExp.$1;
  653. ma = RegExp.$2;
  654.  
  655. if ((ma < 0) || (ma > 32)) {
  656. ferror.set(e, oip + ' - invalid subnet', quiet);
  657. return null;
  658. }
  659. }
  660. else {
  661. ferror.set(e, oip + ' - invalid subnet', quiet);
  662. return null;
  663. }
  664.  
  665. ferror.clear(e);
  666. return ip + ((ma != '') ? ('/' + ma) : '');
  667. }
  668.  
  669. function v_subnet(e, quiet) {
  670. if ((_v_subnet(e, e.value, quiet)) == null) return 0;
  671.  
  672. return 1;
  673. }
  674.  
  675. function _v_domain(e, dom, quiet) {
  676. var s;
  677.  
  678. s = dom.replace(/\s+/g, ' ').trim();
  679. if (s.length > 0) {
  680. s = _v_hostname(e, s, 1, 1, 7, '.', true);
  681. if (s == null) {
  682. ferror.set(e, "Invalid name. Only characters \"A-Z 0-9 . -\" are allowed.", quiet);
  683. return null;
  684. }
  685. }
  686. ferror.clear(e);
  687. return s;
  688. }
  689.  
  690. function v_domain(e, quiet) {
  691. var v;
  692.  
  693. if ((e = E(e)) == null) return 0;
  694. if ((v = _v_domain(e, e.value, quiet)) == null) return 0;
  695.  
  696. e.value = v;
  697. return 1;
  698. }
  699.  
  700. /* IPV6-BEGIN */
  701. function ExpandIPv6Address(ip) {
  702. var a, pre, n, i, fill, post;
  703.  
  704. ip = ip.toLowerCase();
  705. if (!ip.match(/^(::)?([a-f0-9]{1,4}::?){0,7}([a-f0-9]{1,4})(::)?$/)) return null;
  706.  
  707. a = ip.split('::');
  708. switch (a.length) {
  709. case 1:
  710. if (a[0] == '') return null;
  711. pre = a[0].split(':');
  712. if (pre.length != 8) return null;
  713. ip = pre.join(':');
  714. break;
  715. case 2:
  716. pre = a[0].split(':');
  717. post = a[1].split(':');
  718. n = 8 - pre.length - post.length;
  719. for (i=0; i<2; i++) {
  720. if (a[i]=='') n++;
  721. }
  722. if (n < 0) return null;
  723. fill = '';
  724. while (n-- > 0) fill += ':0';
  725. ip = pre.join(':') + fill + ':' + post.join(':');
  726. ip = ip.replace(/^:/, '').replace(/:$/, '');
  727. break;
  728. default:
  729. return null;
  730. }
  731.  
  732. ip = ip.replace(/([a-f0-9]{1,4})/ig, '000$1');
  733. ip = ip.replace(/0{0,3}([a-f0-9]{4})/ig, '$1');
  734. return ip;
  735. }
  736.  
  737. function CompressIPv6Address(ip) {
  738. var a, segments;
  739.  
  740. ip = ExpandIPv6Address(ip);
  741. if (!ip) return null;
  742.  
  743. /* if (ip.match(/(?:^00)|(?:^fe[8-9a-b])|(?:^ff)/)) return null; // not valid routable unicast address */
  744.  
  745. ip = ip.replace(/(^|:)0{1,3}/g, '$1');
  746. ip = ip.replace(/(:0)+$/, '::');
  747. ip = ip.replace(/(?:(?:^|:)0){2,}(?!.*(?:::|(?::0){3,}))/, ':');
  748. return ip;
  749. }
  750.  
  751. function ZeroIPv6PrefixBits(ip, prefix_length) {
  752. var b, c, m, n;
  753. ip = ExpandIPv6Address(ip);
  754. ip = ip.replace(/:/g,'');
  755. n = Math.floor(prefix_length/4);
  756. m = 32 - Math.ceil(prefix_length/4);
  757. b = prefix_length % 4;
  758. if (b != 0)
  759. c = (parseInt(ip.charAt(n), 16) & (0xf << 4-b)).toString(16);
  760. else
  761. c = '';
  762.  
  763. ip = ip.substring(0, n) + c + Array((m%4)+1).join('0') + (m>=4 ? '::' : '');
  764. ip = ip.replace(/([a-f0-9]{4})(?=[a-f0-9])/g,'$1:');
  765. ip = ip.replace(/(^|:)0{1,3}/g, '$1');
  766. return ip;
  767. }
  768.  
  769. function ipv6ton(ip) {
  770. var o, x, i;
  771.  
  772. ip = ExpandIPv6Address(ip);
  773. if (!ip) return 0;
  774.  
  775. o = ip.split(':');
  776. x = '';
  777. for (i = 0; i < 8; ++i) x += (('0x' + o[i]) * 1).hex(4);
  778. return parseInt(x, 16);
  779. }
  780.  
  781. function _v_ipv6_addr(e, ip, ipt, quiet) {
  782. var oip;
  783. var a, b;
  784.  
  785. oip = ip;
  786.  
  787. /* ip range */
  788. if ((ipt) && ip.match(/^(.*)-(.*)$/)) {
  789. a = RegExp.$1;
  790. b = RegExp.$2;
  791. a = CompressIPv6Address(a);
  792. b = CompressIPv6Address(b);
  793. if ((a == null) || (b == null)) {
  794. ferror.set(e, oip + ' - invalid IPv6 address range', quiet);
  795. return null;
  796. }
  797. ferror.clear(e);
  798.  
  799. if (ipv6ton(a) > ipv6ton(b)) return b + '-' + a;
  800. return a + '-' + b;
  801. }
  802.  
  803. /* mask matches */
  804. if ((ipt) && ip.match(/^([A-Fa-f0-9:]+)\/(\d+)$/)) {
  805. a = RegExp.$1;
  806. b = parseInt(RegExp.$2, 10);
  807. a = ExpandIPv6Address(a);
  808. if ((a == null) || (b == null)) {
  809. ferror.set(e, oip + ' - invalid IPv6 address', quiet);
  810. return null;
  811. }
  812. if (b < 0 || b > 128) {
  813. ferror.set(e, oip + ' - invalid CIDR notation on IPv6 address', quiet);
  814. return null;
  815. }
  816. ferror.clear(e);
  817.  
  818. ip = ZeroIPv6PrefixBits(a, b);
  819. return ip + '/' + b.toString(10);
  820. }
  821.  
  822. if ((ipt) && ip.match(/^([A-Fa-f0-9:]+)\/([A-Fa-f0-9:]+)$/)) {
  823. a = RegExp.$1;
  824. b = RegExp.$2;
  825. a = CompressIPv6Address(a);
  826. b = CompressIPv6Address(b);
  827. if ((a == null) || (b == null)) {
  828. ferror.set(e, oip + ' - invalid IPv6 address with mask', quiet);
  829. return null;
  830. }
  831. ferror.clear(e);
  832.  
  833. return ip;
  834. }
  835.  
  836. ip = CompressIPv6Address(oip);
  837. if (!ip) {
  838. ferror.set(e, oip + ' - invalid IPv6 address', quiet);
  839. return null;
  840. }
  841.  
  842. ferror.clear(e);
  843. return ip;
  844. }
  845.  
  846. function v_ipv6_addr(e, quiet) {
  847. if ((e = E(e)) == null) return 0;
  848.  
  849. ip = _v_ipv6_addr(e, e.value, false, quiet);
  850. if (ip) e.value = ip;
  851. return (ip != null);
  852. }
  853. /* IPV6-END */
  854.  
  855. function fixPort(p, def) {
  856. if (def == null) def = -1;
  857. if (p == null) return def;
  858. p *= 1;
  859. if ((isNaN(p) || (p < 1) || (p > 65535) || (('' + p).indexOf('.') != -1))) return def;
  860. return p;
  861. }
  862.  
  863. function _v_portrange(e, quiet, v) {
  864. if (v.match(/^(.*)[-:](.*)$/)) {
  865. var x = RegExp.$1;
  866. var y = RegExp.$2;
  867.  
  868. x = fixPort(x, -1);
  869. y = fixPort(y, -1);
  870. if ((x == -1) || (y == -1)) {
  871. ferror.set(e, 'Invalid port range: ' + v, quiet);
  872. return null;
  873. }
  874. if (x > y) {
  875. v = x;
  876. x = y;
  877. y = v;
  878. }
  879. ferror.clear(e);
  880. if (x == y) return x;
  881. return x + '-' + y;
  882. }
  883.  
  884. v = fixPort(v, -1);
  885. if (v == -1) {
  886. ferror.set(e, 'Invalid port', quiet);
  887. return null;
  888. }
  889.  
  890. ferror.clear(e);
  891. return v;
  892. }
  893.  
  894. function v_portrange(e, quiet) {
  895. var v;
  896.  
  897. if ((e = E(e)) == null) return 0;
  898. v = _v_portrange(e, quiet, e.value);
  899. if (v == null) return 0;
  900. e.value = v;
  901. return 1;
  902. }
  903.  
  904. function v_iptport(e, quiet) {
  905. var a, i, v, q;
  906.  
  907. if ((e = E(e)) == null) return 0;
  908.  
  909. a = e.value.split(/[,\.]/);
  910.  
  911. if (a.length == 0) {
  912. ferror.set(e, 'Expecting a list of ports or port range.', quiet);
  913. return 0;
  914. }
  915. if (a.length > 10) {
  916. ferror.set(e, 'Only 10 ports/range sets are allowed.', quiet);
  917. return 0;
  918. }
  919.  
  920. q = [];
  921. for (i = 0; i < a.length; ++i) {
  922. v = _v_portrange(e, quiet, a[i]);
  923. if (v == null) return 0;
  924. q.push(v);
  925. }
  926.  
  927. e.value = q.join(',');
  928. ferror.clear(e);
  929. return 1;
  930. }
  931.  
  932. function _v_netmask(mask) {
  933. var v = aton(mask) ^ 0xFFFFFFFF;
  934. return (((v + 1) & v) == 0);
  935. }
  936.  
  937. function v_netmask(e, quiet) {
  938. var n, b;
  939.  
  940. if ((e = E(e)) == null) return 0;
  941. n = fixIP(e.value);
  942. if (n) {
  943. if (_v_netmask(n)) {
  944. e.value = n;
  945. ferror.clear(e);
  946. return 1;
  947. }
  948. }
  949. else if (e.value.match(/^\s*\/\s*(\d+)\s*$/)) {
  950. b = RegExp.$1 * 1;
  951. if ((b >= 1) && (b <= 32)) {
  952. if (b == 32)
  953. n = 0xFFFFFFFF; /* js quirk */
  954. else
  955. n = (0xFFFFFFFF >>> b) ^ 0xFFFFFFFF;
  956.  
  957. e.value = (n >>> 24) + '.' + ((n >>> 16) & 0xFF) + '.' + ((n >>> 8) & 0xFF) + '.' + (n & 0xFF);
  958. ferror.clear(e);
  959. return 1;
  960. }
  961. }
  962. ferror.set(e, 'Invalid netmask', quiet);
  963. return 0;
  964. }
  965.  
  966. function fixMAC(mac) {
  967. var t, i;
  968.  
  969. mac = mac.replace(/\s+/g, '').toUpperCase();
  970. if (mac.length == 0) {
  971. mac = [0,0,0,0,0,0];
  972. }
  973. else if (mac.length == 12) {
  974. mac = mac.match(/../g);
  975. }
  976. else {
  977. mac = mac.split(/[:\-]/);
  978. if (mac.length != 6) return null;
  979. }
  980. for (i = 0; i < 6; ++i) {
  981. t = '' + mac[i];
  982. if (t.search(/^[0-9A-F]+$/) == -1) return null;
  983. if ((t = parseInt(t, 16)) > 255) return null;
  984. mac[i] = t.hex(2);
  985. }
  986. return mac.join(':');
  987. }
  988.  
  989. function v_mac(e, quiet) {
  990. var mac;
  991.  
  992. if ((e = E(e)) == null) return 0;
  993. mac = fixMAC(e.value);
  994. if ((!mac) || (isMAC0(mac))) {
  995. ferror.set(e, 'Invalid MAC address', quiet);
  996. return 0;
  997. }
  998. e.value = mac;
  999. ferror.clear(e);
  1000. return 1;
  1001. }
  1002.  
  1003. function v_macz(e, quiet) {
  1004. var mac;
  1005.  
  1006. if ((e = E(e)) == null) return 0;
  1007. mac = fixMAC(e.value);
  1008. if (!mac) {
  1009. ferror.set(e, 'Invalid MAC address', quiet);
  1010. return false;
  1011. }
  1012. e.value = mac;
  1013. ferror.clear(e);
  1014. return true;
  1015. }
  1016.  
  1017. function v_length(e, quiet, min, max) {
  1018. var s, n;
  1019.  
  1020. if ((e = E(e)) == null) return 0;
  1021. s = e.value.trim();
  1022. n = s.length;
  1023. if (min == undefined) min = 1;
  1024. if (n < min) {
  1025. ferror.set(e, 'Invalid length. Please enter at least ' + min + ' character' + (min == 1 ? '.' : 's.'), quiet);
  1026. return 0;
  1027. }
  1028. max = max || e.maxlength;
  1029. if (n > max) {
  1030. ferror.set(e, 'Invalid length. Please reduce the length to ' + max + ' characters or less.', quiet);
  1031. return 0;
  1032. }
  1033. e.value = s;
  1034. ferror.clear(e);
  1035. return 1;
  1036. }
  1037.  
  1038. function _v_iptaddr(e, quiet, multi, ipv4, ipv6) {
  1039. var v, t, i;
  1040.  
  1041. if ((e = E(e)) == null) return 0;
  1042. v = e.value.split(',');
  1043. if (multi) {
  1044. if (v.length > multi) {
  1045. ferror.set(e, 'Too many addresses', quiet);
  1046. return 0;
  1047. }
  1048. }
  1049. else {
  1050. if (v.length > 1) {
  1051. ferror.set(e, 'Invalid domain name or IP address', quiet);
  1052. return 0;
  1053. }
  1054. }
  1055.  
  1056. for (i = 0; i < v.length; ++i) {
  1057. if ((t = _v_domain(e, v[i], 1)) == null) {
  1058. /* IPV6-BEGIN */
  1059. if ((!ipv6) && (!ipv4)) {
  1060. if (!quiet) ferror.show(e);
  1061. return 0;
  1062. }
  1063. if ((!ipv6) || ((t = _v_ipv6_addr(e, v[i], 1, 1)) == null)) {
  1064. /* IPV6-END */
  1065. if (!ipv4) {
  1066. if (!quiet) ferror.show(e);
  1067. return 0;
  1068. }
  1069. if ((t = _v_iptip(e, v[i], 1)) == null) {
  1070. ferror.set(e, e._error_msg + ', or invalid domain name', quiet);
  1071. return 0;
  1072. }
  1073. /* IPV6-BEGIN */
  1074. }
  1075. /* IPV6-END */
  1076. }
  1077. v[i] = t;
  1078. }
  1079.  
  1080. e.value = v.join(', ');
  1081. ferror.clear(e);
  1082. return 1;
  1083. }
  1084.  
  1085. function v_iptaddr(e, quiet, multi) {
  1086. return _v_iptaddr(e, quiet, multi, 1, 0);
  1087. }
  1088.  
  1089. function _v_hostname(e, h, quiet, required, multi, delim, cidr) {
  1090. var s;
  1091. var v, i;
  1092. var re;
  1093.  
  1094. v = (typeof(delim) == 'undefined') ? h.split(/\s+/) : h.split(delim);
  1095.  
  1096. if (multi) {
  1097. if (v.length > multi) {
  1098. ferror.set(e, 'Too many hostnames.', quiet);
  1099. return null;
  1100. }
  1101. }
  1102. else {
  1103. if (v.length > 1) {
  1104. ferror.set(e, 'Invalid hostname.', quiet);
  1105. return null;
  1106. }
  1107. }
  1108.  
  1109. re = /^[a-zA-Z0-9](([a-zA-Z0-9\-]{0,61})[a-zA-Z0-9]){0,1}$/;
  1110.  
  1111. for (i = 0; i < v.length; ++i) {
  1112. s = v[i].replace(/_+/g, '-').replace(/\s+/g, '-');
  1113. if (s.length > 0) {
  1114. if (cidr && i == v.length-1)
  1115. re = /^[a-zA-Z0-9](([a-zA-Z0-9\-]{0,61})[a-zA-Z0-9]){0,1}(\/\d{1,3})?$/;
  1116. if (s.search(re) == -1) {
  1117. var test = s.search(re);
  1118. var test1 = s.search(/^\d+$/);
  1119. console.log(test);
  1120. console.log(test1);
  1121. ferror.set(e, 'Invalid hostname. Only "A-Z 0-9" and "-" in the middle are allowed (up to 63 characters).', quiet);
  1122. return null;
  1123. }
  1124. } else if (required) {
  1125. ferror.set(e, 'Invalid hostname.', quiet);
  1126. return null;
  1127. }
  1128. v[i] = s;
  1129. }
  1130.  
  1131. ferror.clear(e);
  1132. return v.join((typeof(delim) == 'undefined') ? ' ' : delim);
  1133. }
  1134.  
  1135. function v_hostname(e, quiet, multi, delim) {
  1136. var v;
  1137.  
  1138. if ((e = E(e)) == null) return 0;
  1139.  
  1140. v = _v_hostname(e, e.value, quiet, 0, multi, delim, false);
  1141.  
  1142. if (v == null) return 0;
  1143.  
  1144. e.value = v;
  1145. return 1;
  1146. }
  1147.  
  1148. function v_nodelim(e, quiet, name, checklist) {
  1149. if ((e = E(e)) == null) return 0;
  1150.  
  1151. e.value = e.value.trim();
  1152. if (e.value.indexOf('<') != -1 ||
  1153. (checklist && e.value.indexOf('>') != -1)) {
  1154. ferror.set(e, 'Invalid ' + name + ': \"<\" ' + (checklist ? 'or \">\" are' : 'is') + ' not allowed.', quiet);
  1155. return 0;
  1156. }
  1157. ferror.clear(e);
  1158. return 1;
  1159. }
  1160.  
  1161. function v_path(e, quiet, required) {
  1162. if ((e = E(e)) == null) return 0;
  1163. if (required && !v_length(e, quiet, 1)) return 0;
  1164.  
  1165. if (!required && e.value.trim().length == 0) {
  1166. ferror.clear(e);
  1167. return 1;
  1168. }
  1169. if (e.value.substr(0, 1) != '/') {
  1170. ferror.set(e, 'Please start at the / root directory.', quiet);
  1171. return 0;
  1172. }
  1173. ferror.clear(e);
  1174. return 1;
  1175. }
  1176.  
  1177. function isMAC0(mac) {
  1178. return (mac == mac_null);
  1179. }
  1180.  
  1181. // -----------------------------------------------------------------------------
  1182.  
  1183. function cmpIP(a, b) {
  1184. if ((a = fixIP(a)) == null) a = '255.255.255.255';
  1185. if ((b = fixIP(b)) == null) b = '255.255.255.255';
  1186. return aton(a) - aton(b);
  1187. }
  1188.  
  1189. function cmpText(a, b) {
  1190. if (a == '') a = '\xff';
  1191. if (b == '') b = '\xff';
  1192. return (a < b) ? -1 : ((a > b) ? 1 : 0);
  1193. }
  1194.  
  1195. function cmpInt(a, b) {
  1196. a = parseInt(a, 10);
  1197. b = parseInt(b, 10);
  1198. return ((isNaN(a)) ? -0x7FFFFFFF : a) - ((isNaN(b)) ? -0x7FFFFFFF : b);
  1199. }
  1200.  
  1201. function cmpFloat(a, b) {
  1202. a = parseFloat(a);
  1203. b = parseFloat(b);
  1204. return ((isNaN(a)) ? -Number.MAX_VALUE : a) - ((isNaN(b)) ? -Number.MAX_VALUE : b);
  1205. }
  1206.  
  1207. function cmpDate(a, b) {
  1208. return b.getTime() - a.getTime();
  1209. }
  1210.  
  1211. // -----------------------------------------------------------------------------
  1212.  
  1213. // ---- todo: cleanup this mess
  1214.  
  1215. function TGO(e) {
  1216. return elem.parentElem(e, 'TABLE').gridObj;
  1217. }
  1218.  
  1219. function tgHideIcons() {
  1220. var e;
  1221. while ((e = document.getElementById('tg-row-panel')) != null) e.parentNode.removeChild(e);
  1222. }
  1223.  
  1224. // ---- options = sort, move, delete
  1225. function TomatoGrid(tb, options, maxAdd, editorFields) {
  1226. this.init(tb, options, maxAdd, editorFields);
  1227. return this;
  1228. }
  1229.  
  1230. TomatoGrid.prototype = {
  1231. init: function(tb, options, maxAdd, editorFields) {
  1232. if (tb) {
  1233. this.tb = E(tb);
  1234. this.tb.gridObj = this;
  1235.  
  1236. var att_c = this.tb.getAttribute("class");
  1237. var att_s = this.tb.getAttribute("style");
  1238. var table = document.createElement("table");
  1239. if (att_c) table.setAttribute("class", att_c);
  1240. if (att_s) table.setAttribute("style", att_s);
  1241. this.tb.appendChild(table);
  1242. this.tb = E(table);
  1243. this.tb.gridObj = this;
  1244. }
  1245. else {
  1246. this.tb = null;
  1247. }
  1248. if (!options) options = '';
  1249. this.header = null;
  1250. this.footer = null;
  1251. this.editor = null;
  1252. this.canSort = options.indexOf('sort') != -1;
  1253. this.canMove = options.indexOf('move') != -1;
  1254. this.maxAdd = maxAdd || 500;
  1255. this.canEdit = (editorFields != null);
  1256. this.canDelete = this.canEdit || (options.indexOf('delete') != -1);
  1257. this.editorFields = editorFields;
  1258. this.sortColumn = -1;
  1259. this.sortAscending = true;
  1260. },
  1261.  
  1262. _insert: function(at, cells, escCells) {
  1263. var tr, td, c;
  1264. var i, t;
  1265.  
  1266. tr = this.tb.insertRow(at);
  1267. for (i = 0; i < cells.length; ++i) {
  1268. c = cells[i];
  1269. if (typeof(c) == 'string') {
  1270. td = tr.insertCell(i);
  1271. td.className = 'co' + (i + 1);
  1272. if (escCells) td.appendChild(document.createTextNode(c));
  1273. else td.innerHTML = c;
  1274. }
  1275. else {
  1276. tr.appendChild(c);
  1277. }
  1278. }
  1279. return tr;
  1280. },
  1281.  
  1282. // ---- header
  1283.  
  1284. headerClick: function(cell) {
  1285. if (this.canSort) {
  1286. this.sort(cell.cellN);
  1287. }
  1288. },
  1289.  
  1290. headerSet: function(cells, escCells) {
  1291. var e, i;
  1292.  
  1293. elem.remove(this.header);
  1294. this.header = e = this._insert(0, cells, escCells);
  1295. e.className = 'header';
  1296.  
  1297. for (i = 0; i < e.cells.length; ++i) {
  1298. e.cells[i].cellN = i; /* cellIndex broken in Safari */
  1299. e.cells[i].onclick = function() { return TGO(this).headerClick(this); };
  1300. }
  1301. return e;
  1302. },
  1303.  
  1304. // ---- footer
  1305.  
  1306. footerClick: function(cell) {
  1307. },
  1308.  
  1309. footerSet: function(cells, escCells) {
  1310. var e, i;
  1311.  
  1312. elem.remove(this.footer);
  1313. this.footer = e = this._insert(-1, cells, escCells);
  1314. e.className = 'footer';
  1315. for (i = 0; i < e.cells.length; ++i) {
  1316. e.cells[i].cellN = i;
  1317. e.cells[i].onclick = function() { TGO(this).footerClick(this) };
  1318. }
  1319. return e;
  1320. },
  1321.  
  1322. // ----
  1323.  
  1324. rpUp: function(e) {
  1325. var i;
  1326.  
  1327. e = PR(e);
  1328. TGO(e).moving = null;
  1329. i = e.previousSibling;
  1330. if (i == this.header) return;
  1331. e.parentNode.removeChild(e);
  1332. i.parentNode.insertBefore(e, i);
  1333.  
  1334. this.recolor();
  1335. this.rpHide();
  1336. },
  1337.  
  1338. rpDn: function(e) {
  1339. var i;
  1340.  
  1341. e = PR(e);
  1342. TGO(e).moving = null;
  1343. i = e.nextSibling;
  1344. if (i == this.footer) return;
  1345. e.parentNode.removeChild(e);
  1346. i.parentNode.insertBefore(e, i.nextSibling);
  1347.  
  1348. this.recolor();
  1349. this.rpHide();
  1350. },
  1351.  
  1352. rpMo: function(img, e) {
  1353. var me;
  1354.  
  1355. e = PR(e);
  1356. me = TGO(e);
  1357. if (me.moving == e) {
  1358. me.moving = null;
  1359. this.rpHide();
  1360. return;
  1361. }
  1362. me.moving = e;
  1363. img.style.border = "1px dotted red";
  1364. },
  1365.  
  1366. rpDel: function(e) {
  1367. e = PR(e);
  1368. TGO(e).moving = null;
  1369. e.parentNode.removeChild(e);
  1370. this.recolor();
  1371. this.rpHide();
  1372. },
  1373.  
  1374. rpMouIn: function(evt) {
  1375. var e, x, ofs, me, s, n;
  1376.  
  1377. if ((evt = checkEvent(evt)) == null) return;
  1378.  
  1379. me = TGO(evt.target);
  1380. if (me.isEditing()) return;
  1381. if (me.moving) return;
  1382.  
  1383. me.rpHide();
  1384. e = document.createElement('div');
  1385. e.tgo = me;
  1386. e.ref = evt.target;
  1387. e.setAttribute('id', 'tg-row-panel');
  1388.  
  1389. n = 0;
  1390. s = '';
  1391. if (me.canMove) {
  1392. s = '<img src="rpu.gif" onclick="this.parentNode.tgo.rpUp(this.parentNode.ref)" title="Move Up"><img src="rpd.gif" onclick="this.parentNode.tgo.rpDn(this.parentNode.ref)" title="Move Down"><img src="rpm.gif" onclick="this.parentNode.tgo.rpMo(this,this.parentNode.ref)" title="Move">';
  1393. n += 3;
  1394. }
  1395. if (me.canDelete) {
  1396. s += '<img src="rpx.gif" onclick="this.parentNode.tgo.rpDel(this.parentNode.ref)" title="Delete">';
  1397. ++n;
  1398. }
  1399. x = PR(evt.target);
  1400. x = x.cells[x.cells.length - 1];
  1401. ofs = elem.getOffset(x);
  1402. n *= 18;
  1403. e.style.left = (ofs.x + x.offsetWidth - n) + 'px';
  1404. e.style.top = ofs.y + 'px';
  1405. e.style.width = n + 'px';
  1406. e.innerHTML = s;
  1407.  
  1408. document.body.appendChild(e);
  1409. },
  1410.  
  1411. rpHide: tgHideIcons,
  1412.  
  1413. // ----
  1414.  
  1415. onClick: function(cell) {
  1416. if (this.canEdit) {
  1417. if (this.moving) {
  1418. var p = this.moving.parentNode;
  1419. var q = PR(cell);
  1420. if (this.moving != q) {
  1421. var v = this.moving.rowIndex > q.rowIndex;
  1422. p.removeChild(this.moving);
  1423. if (v)
  1424. p.insertBefore(this.moving, q);
  1425. else
  1426. p.insertBefore(this.moving, q.nextSibling);
  1427.  
  1428. this.recolor();
  1429. }
  1430. this.moving = null;
  1431. this.rpHide();
  1432. return;
  1433. }
  1434. this.edit(cell);
  1435. }
  1436. },
  1437.  
  1438. insert: function(at, data, cells, escCells) {
  1439. var e, i;
  1440.  
  1441. if ((this.footer) && (at == -1)) at = this.footer.rowIndex;
  1442. e = this._insert(at, cells, escCells);
  1443. e.className = (e.rowIndex & 1) ? 'even' : 'odd';
  1444.  
  1445. for (i = 0; i < e.cells.length; ++i) {
  1446. e.cells[i].onclick = function() { return TGO(this).onClick(this); };
  1447. }
  1448.  
  1449. e._data = data;
  1450. e.getRowData = function() { return this._data; }
  1451. e.setRowData = function(data) { this._data = data; }
  1452.  
  1453. if ((this.canMove) || (this.canEdit) || (this.canDelete)) {
  1454. e.onmouseover = this.rpMouIn;
  1455. // ---- e.onmouseout = this.rpMouOut;
  1456. if (this.canEdit) e.title = 'Click to edit';
  1457. }
  1458.  
  1459. return e;
  1460. },
  1461.  
  1462. // ----
  1463.  
  1464. insertData: function(at, data) {
  1465. return this.insert(at, data, this.dataToView(data), false);
  1466. },
  1467.  
  1468. dataToView: function(data) {
  1469. var v = [];
  1470. for (var i = 0; i < data.length; ++i) {
  1471. var s = escapeHTML('' + data[i]);
  1472. if (this.editorFields && this.editorFields.length > i) {
  1473. var ef = this.editorFields[i].multi;
  1474. if (!ef) ef = [this.editorFields[i]];
  1475. var f = (ef && ef.length > 0 ? ef[0] : null);
  1476. if (f && f.type == 'password') {
  1477. if (!f.peekaboo || get_config('web_pb', '1') != '0')
  1478. s = s.replace(/./g, '&#x25CF;');
  1479. }
  1480. }
  1481. v.push(s);
  1482. }
  1483. return v;
  1484. },
  1485.  
  1486. dataToFieldValues: function(data) {
  1487. return data;
  1488. },
  1489.  
  1490. fieldValuesToData: function(row) {
  1491. var e, i, data;
  1492.  
  1493. data = [];
  1494. e = fields.getAll(row);
  1495. for (i = 0; i < e.length; ++i) data.push(e[i].value);
  1496. return data;
  1497. },
  1498.  
  1499. // ----
  1500.  
  1501. edit: function(cell) {
  1502. var sr, er, e, c;
  1503.  
  1504. if (this.isEditing()) return;
  1505.  
  1506. sr = PR(cell);
  1507. sr.style.display = 'none';
  1508. elem.removeClass(sr, 'hover');
  1509. this.source = sr;
  1510.  
  1511. er = this.createEditor('edit', sr.rowIndex, sr);
  1512. er.className = 'editor';
  1513. this.editor = er;
  1514.  
  1515. c = er.cells[cell.cellIndex || 0];
  1516. e = c.getElementsByTagName('input');
  1517. if ((e) && (e.length > 0)) {
  1518. try { /* IE quirk */
  1519. e[0].focus();
  1520. }
  1521. catch (ex) {
  1522. }
  1523. }
  1524.  
  1525. this.controls = this.createControls('edit', sr.rowIndex);
  1526.  
  1527. this.disableNewEditor(true);
  1528. this.rpHide();
  1529. this.verifyFields(this.editor, true);
  1530. },
  1531.  
  1532. createEditor: function(which, rowIndex, source) {
  1533. var values;
  1534.  
  1535. if (which == 'edit') values = this.dataToFieldValues(source.getRowData());
  1536.  
  1537. var row = this.tb.insertRow(rowIndex);
  1538. row.className = 'editor';
  1539.  
  1540. var common = ' onkeypress="return TGO(this).onKey(\'' + which + '\', event)" onchange="TGO(this).onChange(\'' + which + '\', this)"';
  1541.  
  1542. var vi = 0;
  1543. for (var i = 0; i < this.editorFields.length; ++i) {
  1544. var s = '';
  1545. var ef = this.editorFields[i].multi;
  1546. if (!ef) ef = [this.editorFields[i]];
  1547.  
  1548. for (var j = 0; j < ef.length; ++j) {
  1549. var f = ef[j];
  1550.  
  1551. if (f.prefix) s += f.prefix;
  1552. var attrib = ' class="fi' + (vi + 1) + '" ' + (f.attrib || '');
  1553. var id = (this.tb.parentElement.id ? ('_'+this.tb.parentElement.id+'_'+(vi + 1)) : null);
  1554. if (id) attrib += ' id="'+id+'"';
  1555. switch (f.type) {
  1556. case 'password':
  1557. if (f.peekaboo) {
  1558. switch (get_config('web_pb', '1')) {
  1559. case '0':
  1560. f.type = 'text';
  1561. case '2':
  1562. f.peekaboo = 0;
  1563. break;
  1564. }
  1565. }
  1566. attrib += ' autocomplete="off"';
  1567. if (f.peekaboo && id) attrib += ' onfocus="peekaboo(\''+id+'\',1)"';
  1568. /* drop */
  1569. case 'text':
  1570. s += '<input type="' + f.type + '" maxlength=' + f.maxlen + common + attrib;
  1571. if (which == 'edit')
  1572. s += ' value="' + escapeHTML('' + values[vi]) + '">';
  1573. else
  1574. s += '>';
  1575. break;
  1576. case 'clear':
  1577. s += '';
  1578. break;
  1579. case 'select':
  1580. s += '<select' + common + attrib + '>';
  1581. for (var k = 0; k < f.options.length; ++k) {
  1582. var a = f.options[k];
  1583. if (which == 'edit') {
  1584. s += '<option value="' + a[0] + '"' + ((a[0] == values[vi]) ? ' selected="selected">' : '>') + a[1] + '</option>';
  1585. }
  1586. else {
  1587. s += '<option value="' + a[0] + '">' + a[1] + '</option>';
  1588. }
  1589. }
  1590. s += '</select>';
  1591. break;
  1592. case 'checkbox':
  1593. s += '<input type="checkbox"' + common + attrib;
  1594. if ((which == 'edit') && (values[vi])) s += ' checked="checked"';
  1595. s += '>';
  1596. break;
  1597. case 'textarea':
  1598. if (which == 'edit') {
  1599. document.getElementById(f.proxy).value = values[vi];
  1600. }
  1601. break;
  1602. default:
  1603. s += f.custom.replace(/\$which\$/g, which);
  1604. }
  1605. if (f.suffix) s += f.suffix;
  1606.  
  1607. ++vi;
  1608. }
  1609. if (this.editorFields[i].type != 'textarea'){
  1610. var c = row.insertCell(i);
  1611. c.innerHTML = s;
  1612. if (this.editorFields[i].vtop) c.style = 'vertical-align:top';
  1613. }
  1614. }
  1615.  
  1616. return row;
  1617. },
  1618.  
  1619. createControls: function(which, rowIndex) {
  1620. var r, c;
  1621.  
  1622. r = this.tb.insertRow(rowIndex);
  1623. r.className = 'controls';
  1624.  
  1625. c = r.insertCell(0);
  1626. c.colSpan = this.header.cells.length;
  1627. if (which == 'edit') {
  1628. c.innerHTML =
  1629. '<input type=button value="Delete" onclick="TGO(this).onDelete()"> &nbsp; ' +
  1630. '<input type=button value="OK" onclick="TGO(this).onOK()"> ' +
  1631. '<input type=button value="Cancel" onclick="TGO(this).onCancel()">';
  1632. }
  1633. else {
  1634. c.innerHTML =
  1635. '<input type=button value="Add" onclick="TGO(this).onAdd()">';
  1636. }
  1637. return r;
  1638. },
  1639.  
  1640. removeEditor: function() {
  1641. if (this.editor) {
  1642.  
  1643. elem.remove(this.editor);
  1644. this.editor = null;
  1645. }
  1646. if (this.controls) {
  1647. elem.remove(this.controls);
  1648. this.controls = null;
  1649. }
  1650. },
  1651.  
  1652. showSource: function() {
  1653. if (this.source) {
  1654. this.source.style.display = '';
  1655. this.source = null;
  1656. }
  1657. },
  1658.  
  1659. onChange: function(which, cell) {
  1660. return this.verifyFields((which == 'new') ? this.newEditor : this.editor, true);
  1661. },
  1662.  
  1663. onKey: function(which, ev) {
  1664. switch (ev.keyCode) {
  1665. case 27:
  1666. if (which == 'edit') this.onCancel();
  1667. return false;
  1668. case 13:
  1669. if (((ev.srcElement) && (ev.srcElement.tagName == 'SELECT')) || ((ev.target) && (ev.target.tagName == 'SELECT'))) return true;
  1670. if (which == 'edit')
  1671. this.onOK();
  1672. else
  1673. this.onAdd();
  1674.  
  1675. return false;
  1676. }
  1677. return true;
  1678. },
  1679.  
  1680. onDelete: function() {
  1681. this.removeEditor();
  1682. elem.remove(this.source);
  1683. this.source = null;
  1684. this.disableNewEditor(false);
  1685. this.clearTextarea();
  1686. },
  1687.  
  1688. onCancel: function() {
  1689. this.removeEditor();
  1690. this.showSource();
  1691. this.disableNewEditor(false);
  1692. this.clearTextarea();
  1693. },
  1694.  
  1695. onOK: function() {
  1696. var i, data, view;
  1697.  
  1698. if (!this.verifyFields(this.editor, false)) return;
  1699.  
  1700. data = this.fieldValuesToData(this.editor);
  1701. view = this.dataToView(data);
  1702.  
  1703. this.source.setRowData(data);
  1704. for (i = 0; i < this.source.cells.length; ++i) {
  1705. this.source.cells[i].innerHTML = view[i];
  1706. }
  1707.  
  1708. this.removeEditor();
  1709. this.showSource();
  1710. this.disableNewEditor(false);
  1711. this.clearTextarea();
  1712. },
  1713.  
  1714. onAdd: function() {
  1715. var data;
  1716.  
  1717. this.moving = null;
  1718. this.rpHide();
  1719.  
  1720. if (!this.verifyFields(this.newEditor, false)) return;
  1721.  
  1722. data = this.fieldValuesToData(this.newEditor);
  1723. this.insertData(-1, data);
  1724.  
  1725. this.disableNewEditor(false);
  1726. this.resetNewEditor();
  1727. },
  1728.  
  1729. clearTextarea: function() {
  1730. for (var i = 0; i < this.editorFields.length; ++i){
  1731. if (this.editorFields[i].type == 'textarea'){
  1732. document.getElementById(this.editorFields[i].proxy).value = '';
  1733. ferror.clear(document.getElementById(this.editorFields[i].proxy));
  1734. }
  1735. }
  1736. },
  1737.  
  1738. verifyFields: function(row, quiet) {
  1739. return true;
  1740. },
  1741.  
  1742. showNewEditor: function() {
  1743. var r;
  1744.  
  1745. r = this.createEditor('new', -1, null);
  1746. this.footer = this.newEditor = r;
  1747.  
  1748. r = this.createControls('new', -1);
  1749. this.newControls = r;
  1750.  
  1751. this.disableNewEditor(false);
  1752. },
  1753.  
  1754. disableNewEditor: function(disable) {
  1755. if (this.getDataCount() >= this.maxAdd) disable = true;
  1756. if (this.newEditor) fields.disableAll(this.newEditor, disable);
  1757. if (this.newControls) fields.disableAll(this.newControls, disable);
  1758. },
  1759.  
  1760. resetNewEditor: function() {
  1761. var i, e;
  1762.  
  1763. e = fields.getAll(this.newEditor);
  1764. ferror.clearAll(e);
  1765. for (i = 0; i < e.length; ++i) {
  1766. var f = e[i];
  1767. if (f.selectedIndex)
  1768. f.selectedIndex = 0;
  1769. else
  1770. f.value = '';
  1771. }
  1772. try { if (e.length) e[0].focus(); } catch (er) { }
  1773. },
  1774.  
  1775. getDataCount: function() {
  1776. var n;
  1777. n = this.tb.rows.length;
  1778. if (this.footer) n = this.footer.rowIndex;
  1779. if (this.header) n -= this.header.rowIndex + 1;
  1780. return n;
  1781. },
  1782.  
  1783. sortCompare: function(a, b) {
  1784. var obj = TGO(a);
  1785. var col = obj.sortColumn;
  1786. var r = cmpText(a.cells[col].innerHTML, b.cells[col].innerHTML);
  1787. return obj.sortAscending ? r : -r;
  1788. },
  1789.  
  1790. sort: function(column) {
  1791. if (this.editor) return;
  1792.  
  1793. if (this.sortColumn >= 0) {
  1794. elem.removeClass(this.header.cells[this.sortColumn], 'sortasc', 'sortdes');
  1795. }
  1796. if (column == this.sortColumn) {
  1797. this.sortAscending = !this.sortAscending;
  1798. }
  1799. else {
  1800. this.sortAscending = true;
  1801. this.sortColumn = column;
  1802. }
  1803. elem.addClass(this.header.cells[column], this.sortAscending ? 'sortasc' : 'sortdes');
  1804.  
  1805. this.resort();
  1806. },
  1807.  
  1808. resort: function() {
  1809. if ((this.sortColumn < 0) || (this.getDataCount() == 0) || (this.editor)) return;
  1810.  
  1811. var p = this.header.parentNode;
  1812. var a = [];
  1813. var i, j, max, e, p;
  1814. var top;
  1815.  
  1816. this.moving = null;
  1817.  
  1818. top = this.header ? this.header.rowIndex + 1 : 0;
  1819. max = this.footer ? this.footer.rowIndex : this.tb.rows.length;
  1820. for (i = top; i < max; ++i) a.push(p.rows[i]);
  1821. a.sort(THIS(this, this.sortCompare));
  1822. this.removeAllData();
  1823. j = top;
  1824. for (i = 0; i < a.length; ++i) {
  1825. e = p.insertBefore(a[i], this.footer);
  1826. e.className = (j & 1) ? 'even' : 'odd';
  1827. ++j;
  1828. }
  1829. },
  1830.  
  1831. recolor: function() {
  1832. var i, e, o;
  1833.  
  1834. i = this.header ? this.header.rowIndex + 1 : 0;
  1835. e = this.footer ? this.footer.rowIndex : this.tb.rows.length;
  1836. for (; i < e; ++i) {
  1837. o = this.tb.rows[i];
  1838. o.className = (o.rowIndex & 1) ? 'even' : 'odd';
  1839. }
  1840. },
  1841.  
  1842. removeAllData: function() {
  1843. var i, count;
  1844.  
  1845. i = this.header ? this.header.rowIndex + 1 : 0;
  1846. count = (this.footer ? this.footer.rowIndex : this.tb.rows.length) - i;
  1847. while (count-- > 0) elem.remove(this.tb.rows[i]);
  1848. },
  1849.  
  1850. getAllData: function() {
  1851. var i, max, data, r;
  1852.  
  1853. data = [];
  1854. max = this.footer ? this.footer.rowIndex : this.tb.rows.length;
  1855. for (i = this.header ? this.header.rowIndex + 1 : 0; i < max; ++i) {
  1856. r = this.tb.rows[i];
  1857. if ((r.style.display != 'none') && (r._data)) data.push(r._data);
  1858. }
  1859. return data;
  1860. },
  1861.  
  1862. isEditing: function() {
  1863. return (this.editor != null);
  1864. }
  1865. }
  1866.  
  1867.  
  1868. // -----------------------------------------------------------------------------
  1869.  
  1870.  
  1871. function xmlHttpObj() {
  1872. var ob;
  1873. try {
  1874. ob = new XMLHttpRequest();
  1875. if (ob) return ob;
  1876. }
  1877. catch (ex) { }
  1878. try {
  1879. ob = new ActiveXObject('Microsoft.XMLHTTP');
  1880. if (ob) return ob;
  1881. }
  1882. catch (ex) { }
  1883. return null;
  1884. }
  1885.  
  1886. var _useAjax = -1;
  1887. var _holdAjax = null;
  1888.  
  1889. function useAjax() {
  1890. if (_useAjax == -1) _useAjax = ((_holdAjax = xmlHttpObj()) != null);
  1891. return _useAjax;
  1892. }
  1893.  
  1894. function XmlHttp() {
  1895. if ((!useAjax()) || ((this.xob = xmlHttpObj()) == null)) return null;
  1896. return this;
  1897. }
  1898.  
  1899. XmlHttp.prototype = {
  1900. addId: function(vars) {
  1901. if (vars)
  1902. vars += '&';
  1903. else
  1904. vars = '';
  1905.  
  1906. vars += '_http_id=' + escapeCGI(nvram.http_id);
  1907. return vars;
  1908. },
  1909.  
  1910. get: function(url, vars) {
  1911. try {
  1912. vars = this.addId(vars);
  1913. url += '?' + vars;
  1914.  
  1915. this.xob.onreadystatechange = THIS(this, this.onReadyStateChange);
  1916. this.xob.open('GET', url, true);
  1917. this.xob.send(null);
  1918. }
  1919. catch (ex) {
  1920. this.onError(ex);
  1921. }
  1922. },
  1923.  
  1924. post: function(url, vars) {
  1925. try {
  1926. vars = this.addId(vars);
  1927.  
  1928. this.xob.onreadystatechange = THIS(this, this.onReadyStateChange);
  1929. this.xob.open('POST', url, true);
  1930. this.xob.send(vars);
  1931. }
  1932. catch (ex) {
  1933. this.onError(ex);
  1934. }
  1935. },
  1936.  
  1937. abort: function() {
  1938. try {
  1939. this.xob.onreadystatechange = function () { }
  1940. this.xob.abort();
  1941. }
  1942. catch (ex) {
  1943. }
  1944. },
  1945.  
  1946. onReadyStateChange: function() {
  1947. try {
  1948. if (typeof(E) == 'undefined') return; /* oddly late? testing for bug... */
  1949.  
  1950. if (this.xob.readyState == 4) {
  1951. if (this.xob.status == 200) {
  1952. this.onCompleted(this.xob.responseText, this.xob.responseXML);
  1953. }
  1954. else {
  1955. this.onError('' + (this.xob.status || 'unknown'));
  1956. }
  1957. }
  1958. }
  1959. catch (ex) {
  1960. this.onError(ex);
  1961. }
  1962. },
  1963.  
  1964. onCompleted: function(text, xml) { },
  1965. onError: function(ex) { }
  1966. }
  1967.  
  1968.  
  1969. // -----------------------------------------------------------------------------
  1970.  
  1971.  
  1972. function TomatoTimer(func, ms) {
  1973. this.tid = null;
  1974. this.onTimer = func;
  1975. if (ms) this.start(ms);
  1976. return this;
  1977. }
  1978.  
  1979. TomatoTimer.prototype = {
  1980. start: function(ms) {
  1981. this.stop();
  1982. this.tid = setTimeout(THIS(this, this._onTimer), ms);
  1983. },
  1984. stop: function() {
  1985. if (this.tid) {
  1986. clearTimeout(this.tid);
  1987. this.tid = null;
  1988. }
  1989. },
  1990.  
  1991. isRunning: function() {
  1992. return (this.tid != null);
  1993. },
  1994.  
  1995. _onTimer: function() {
  1996. this.tid = null;
  1997. this.onTimer();
  1998. },
  1999.  
  2000. onTimer: function() {
  2001. }
  2002. }
  2003.  
  2004.  
  2005. // -----------------------------------------------------------------------------
  2006.  
  2007.  
  2008. function TomatoRefresh(actionURL, postData, refreshTime, cookieTag, dontuseButton) {
  2009. this.setup(actionURL, postData, refreshTime, cookieTag, dontuseButton);
  2010. this.timer = new TomatoTimer(THIS(this, this.start));
  2011. }
  2012.  
  2013. TomatoRefresh.prototype = {
  2014. running: 0,
  2015.  
  2016. setup: function(actionURL, postData, refreshTime, cookieTag, dontuseButton) {
  2017. var e, v;
  2018.  
  2019. this.actionURL = actionURL;
  2020. this.postData = postData;
  2021. this.refreshTime = refreshTime * 1000;
  2022. this.cookieTag = cookieTag;
  2023. this.dontuseButton = dontuseButton;
  2024. },
  2025.  
  2026. start: function() {
  2027. var e;
  2028.  
  2029. if ((e = E('refresh-time')) != null) {
  2030. if (this.cookieTag)
  2031. cookie.set(this.cookieTag, e.value);
  2032.  
  2033. if (this.dontuseButton != 1)
  2034. this.refreshTime = e.value * 1000;
  2035. }
  2036.  
  2037. this.updateUI('start');
  2038.  
  2039. if ((e = E('refresh-button')) != null) {
  2040. if (e.value == 'Refresh')
  2041. this.once = 1;
  2042. }
  2043.  
  2044. e = undefined;
  2045.  
  2046. this.running = 1;
  2047. if ((this.http = new XmlHttp()) == null) {
  2048. reloadPage();
  2049. return;
  2050. }
  2051.  
  2052. this.http.parent = this;
  2053.  
  2054. this.http.onCompleted = function(text, xml) {
  2055. var p = this.parent;
  2056.  
  2057. if (p.cookieTag)
  2058. cookie.unset(p.cookieTag + '-error');
  2059. if (!p.running) {
  2060. p.stop();
  2061. return;
  2062. }
  2063.  
  2064. p.refresh(text);
  2065.  
  2066. if ((p.refreshTime > 0) && (!p.once)) {
  2067. p.updateUI('wait');
  2068. p.timer.start(Math.round(p.refreshTime));
  2069. }
  2070. else
  2071. p.stop();
  2072.  
  2073. p.errors = 0;
  2074. }
  2075.  
  2076. this.http.onError = function(ex) {
  2077. var p = this.parent;
  2078. if ((!p) || (!p.running))
  2079. return;
  2080.  
  2081. p.timer.stop();
  2082.  
  2083. if (++p.errors <= 3) {
  2084. p.updateUI('wait');
  2085. p.timer.start(3000);
  2086. return;
  2087. }
  2088.  
  2089. if (p.cookieTag) {
  2090. var e = cookie.get(p.cookieTag + '-error') * 1;
  2091. if (isNaN(e))
  2092. e = 0;
  2093. else
  2094. ++e;
  2095.  
  2096. cookie.unset(p.cookieTag);
  2097. cookie.set(p.cookieTag + '-error', e, 1);
  2098. if (e >= 3) {
  2099. alert('XMLHTTP: ' + ex);
  2100. return;
  2101. }
  2102. }
  2103.  
  2104. setTimeout(reloadPage, 2000);
  2105. }
  2106.  
  2107. this.errors = 0;
  2108. this.http.post(this.actionURL, this.postData);
  2109. },
  2110.  
  2111. stop: function() {
  2112. if (this.cookieTag)
  2113. cookie.set(this.cookieTag, -(this.refreshTime / 1000));
  2114.  
  2115. this.running = 0;
  2116. this.updateUI('stop');
  2117. this.timer.stop();
  2118. this.http = null;
  2119. this.once = undefined;
  2120. },
  2121.  
  2122. toggle: function(delay) {
  2123. if (this.running)
  2124. this.stop();
  2125. else
  2126. this.start(delay);
  2127. },
  2128.  
  2129. updateUI: function(mode) {
  2130. var e, b;
  2131.  
  2132. if (typeof(E) == 'undefined') /* for a bizzare bug... */
  2133. return;
  2134.  
  2135. if (this.dontuseButton != 1) {
  2136. b = (mode != 'stop') && (this.refreshTime > 0);
  2137.  
  2138. if ((e = E('refresh-button')) != null) {
  2139. e.value = b ? 'Stop' : 'Refresh';
  2140. ((mode == 'start') && (!b) ? e.setAttribute('disabled', 'disabled') : e.removeAttribute('disabled'));
  2141. }
  2142.  
  2143. if ((e = E('refresh-time')) != null)
  2144. ((!b) ? e.removeAttribute('disabled') : e.setAttribute('disabled', 'disabled'));
  2145. if ((e = E('refresh-spinner')) != null)
  2146. e.style.display = (b ? 'inline-block' : 'none');
  2147. }
  2148. },
  2149.  
  2150. initPage: function(delay, refresh) {
  2151. var e, v;
  2152.  
  2153. e = E('refresh-time');
  2154. if (((this.cookieTag) && (e != null)) && ((v = cookie.get(this.cookieTag)) != null) && (!isNaN(v *= 1))) {
  2155. e.value = Math.abs(v);
  2156. if (v > 0)
  2157. v = v * 1000;
  2158. }
  2159. else if (refresh) {
  2160. v = refresh * 1000;
  2161. if ((e != null) && (this.dontuseButton != 1))
  2162. e.value = refresh;
  2163. }
  2164. else
  2165. v = 0;
  2166.  
  2167. if (delay < 0) {
  2168. v = -delay;
  2169. this.once = 1;
  2170. }
  2171.  
  2172. if (v > 0) {
  2173. this.running = 1;
  2174. this.refreshTime = v;
  2175. this.timer.start(delay);
  2176. this.updateUI('wait');
  2177. }
  2178. }
  2179. }
  2180.  
  2181. function genStdTimeList(id, zero, min) {
  2182. var b = [];
  2183. var t = [1,2,3,4,5,6,7,8,9,10,12,15,20,25,30,45,60];
  2184. var i, v;
  2185.  
  2186. if (min >= 0) {
  2187. b.push('<select id="' + id + '"><option value="0">' + zero);
  2188. for (i = 0; i < t.length; ++i) {
  2189. v = t[i];
  2190. if (v < min) continue;
  2191. b.push('<option value=' + v + '>');
  2192. if (v == 60)
  2193. b.push('1 minute');
  2194. else if (v > 60)
  2195. b.push((v / 60) + ' minutes');
  2196. else
  2197. b.push(v + ' seconds');
  2198. }
  2199. b.push('</select> ');
  2200. }
  2201. document.write(b.join(''));
  2202. }
  2203.  
  2204. function genStdRefresh(spin, min, exec) {
  2205. W('<div style="text-align:right">');
  2206. if (spin) W('<img src="spin.gif" id="refresh-spinner" alt=""> ');
  2207. genStdTimeList('refresh-time', 'One off', min);
  2208. W('<input type="button" value="Refresh" onclick="' + (exec ? exec : 'refreshClick()') + '" id="refresh-button"></div>');
  2209. }
  2210.  
  2211.  
  2212. // -----------------------------------------------------------------------------
  2213.  
  2214.  
  2215. function _tabCreate(tabs) {
  2216. var buf = [];
  2217. buf.push('<ul id="tabs">');
  2218. for (var i = 0; i < arguments.length; ++i)
  2219. buf.push('<li><a href="javascript:tabSelect(\'' + arguments[i][0] + '\')" id="' + arguments[i][0] + '">' + arguments[i][1] + '</a>');
  2220. buf.push('</ul><div id="tabs-bottom"></div>');
  2221. return buf.join('');
  2222. }
  2223.  
  2224. function tabCreate(tabs) {
  2225. document.write(_tabCreate.apply(this, arguments));
  2226. }
  2227.  
  2228. function tabHigh(id) {
  2229. var a = E('tabs').getElementsByTagName('A');
  2230. for (var i = 0; i < a.length; ++i) {
  2231. if (id != a[i].id) elem.removeClass(a[i], 'active');
  2232. }
  2233. elem.addClass(id, 'active');
  2234. }
  2235.  
  2236. // -----------------------------------------------------------------------------
  2237.  
  2238. var cookie = {
  2239. /*
  2240. The value 2147483647000 is ((2^31)-1)*1000, which is the number of
  2241. milliseconds (minus 1 second) which correlates with the year 2038 counter
  2242. rollover. This effectively makes the cookie never expire.
  2243. */
  2244. set: function(key, value, days) {
  2245. document.cookie = 'tomato_' + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '; expires=' +
  2246. new Date(2147483647000).toUTCString() + '; path=/; SameSite=Lax';
  2247. },
  2248. get: function(key) {
  2249. var r = ('; ' + document.cookie + ';').match('; tomato_' + encodeURIComponent(key) + '=(.*?);');
  2250. return r ? decodeURIComponent(r[1]) : null;
  2251. },
  2252. unset: function(key) {
  2253. document.cookie = 'tomato_' + encodeURIComponent(key) + '=; expires=' +
  2254. (new Date(1)).toUTCString() + '; path=/; SameSite=Lax';
  2255. }
  2256. };
  2257.  
  2258. // -----------------------------------------------------------------------------
  2259.  
  2260. function checkEvent(evt) {
  2261. if (typeof(evt) == 'undefined') {
  2262. // ---- IE
  2263. evt = event;
  2264. evt.target = evt.srcElement;
  2265. evt.relatedTarget = evt.toElement;
  2266. }
  2267. return evt;
  2268. }
  2269.  
  2270. function W(s) {
  2271. document.write(s);
  2272. }
  2273.  
  2274. function E(e) {
  2275. return (typeof(e) == 'string') ? document.getElementById(e) : e;
  2276. }
  2277.  
  2278. function PR(e) {
  2279. return elem.parentElem(e, 'TR');
  2280. }
  2281.  
  2282. function THIS(obj, func) {
  2283. return function() { return func.apply(obj, arguments); }
  2284. }
  2285.  
  2286. function UT(v) {
  2287. return (typeof(v) == 'undefined') ? '' : '' + v;
  2288. }
  2289.  
  2290. function escapeHTML(s) {
  2291. function esc(c) {
  2292. return '&#' + c.charCodeAt(0) + ';';
  2293. }
  2294. return s.replace(/[&"'<>\r\n]/g, esc);
  2295. }
  2296.  
  2297. function escapeCGI(s) {
  2298. return encodeURIComponent(s);
  2299. }
  2300.  
  2301. function escapeD(s) {
  2302. function esc(c) {
  2303. return '%' + c.charCodeAt(0).hex(2);
  2304. }
  2305. return s.replace(/[<>|%]/g, esc);
  2306. }
  2307.  
  2308. function ellipsis(s, max) {
  2309. return (s.length <= max) ? s : s.substr(0, max - 3) + '...';
  2310. }
  2311.  
  2312. function MIN(a, b) {
  2313. return (a < b) ? a : b;
  2314. }
  2315.  
  2316. function MAX(a, b) {
  2317. return (a > b) ? a : b;
  2318. }
  2319.  
  2320. function fixInt(n, min, max, def) {
  2321. if (n === null) return def;
  2322. n *= 1;
  2323. if (isNaN(n)) return def;
  2324. if (n < min) return min;
  2325. if (n > max) return max;
  2326. return n;
  2327. }
  2328.  
  2329. function comma(n) {
  2330. n = '' + n;
  2331. var p = n;
  2332. while ((n = n.replace(/(\d+)(\d{3})/g, '$1,$2')) != p) p = n;
  2333. return n;
  2334. }
  2335.  
  2336. function doScaleSize(n, sm) {
  2337. if (isNaN(n *= 1)) return '-';
  2338. if (n <= 9999) return '' + n + '<small> B</small>';
  2339. var s = -1;
  2340. do {
  2341. n /= 1024;
  2342. ++s;
  2343. } while ((n > 9999) && (s < 2));
  2344. return comma(n.toFixed(2)) + (sm ? '<small> ' : ' ') + (['KB', 'MB', 'GB'])[s] + (sm ? '</small>' : '');
  2345. }
  2346.  
  2347. function scaleSize(n) {
  2348. return doScaleSize(n, 1);
  2349. }
  2350.  
  2351. function timeString(mins) {
  2352. var h = Math.floor(mins / 60);
  2353. if ((new Date(2000, 0, 1, 23, 0, 0, 0)).toLocaleString().indexOf('23') != -1)
  2354. return h + ':' + (mins % 60).pad(2);
  2355. return ((h == 0) ? 12 : ((h > 12) ? h - 12 : h)) + ':' + (mins % 60).pad(2) + ((h >= 12) ? ' PM' : ' AM');
  2356. }
  2357.  
  2358. function features(s) {
  2359. var features = ['ses','brau','aoss','wham','hpamp','!nve','11n','1000et','11ac','11acwave2'];
  2360. var i;
  2361.  
  2362. for (i = features.length - 1; i >= 0; --i) {
  2363. if (features[i] == s) return (parseInt(nvram.t_features) & (1 << i)) != 0;
  2364. }
  2365. return 0;
  2366. }
  2367.  
  2368. function get_config(name, def) {
  2369. return ((typeof(nvram) != 'undefined') && (typeof(nvram[name]) != 'undefined')) ? nvram[name] : def;
  2370. }
  2371.  
  2372. function nothing() {
  2373. }
  2374.  
  2375. // -----------------------------------------------------------------------------
  2376.  
  2377. function show_notice1(s) {
  2378. // ---- !!TB - USB Support: multi-line notices
  2379. if (s.length) document.write('<div id="notice">' + s.replace(/\n/g, '<br>') + '</div><br style="clear:both">');
  2380. }
  2381.  
  2382. // -----------------------------------------------------------------------------
  2383.  
  2384. function getColor(classname) {
  2385. var styleSheets = document.styleSheets;
  2386. for (var i = 0; i < styleSheets.length; i++) {
  2387. if (styleSheets[i].rules)
  2388. var classes = styleSheets[i].rules;
  2389. else {
  2390. try {
  2391. if (!styleSheets[i].cssRules)
  2392. continue;
  2393. }
  2394.  
  2395. catch(e) {
  2396. if (e.name == 'SecurityError')
  2397. continue;
  2398. }
  2399. var classes = styleSheets[i].cssRules;
  2400. }
  2401. for (var x = 0; x < classes.length; x++) {
  2402. if (classes[x].selectorText == classname)
  2403. return classes[x].style.color;
  2404. }
  2405. }
  2406. }
  2407.  
  2408. function checkSVG() {
  2409. var i, e, d, w;
  2410.  
  2411. try {
  2412. for (i = 2; i >= 0; --i) {
  2413. e = E('svg'+i);
  2414. d = e.getSVGDocument();
  2415.  
  2416. if (d.defaultView)
  2417. w = d.defaultView;
  2418. else
  2419. w = e.getWindow();
  2420.  
  2421. if (!w.ready)
  2422. break;
  2423.  
  2424. switch (i) {
  2425. case 0: {
  2426. updateCD = w.updateSVG;
  2427. break;
  2428. }
  2429. case 1: {
  2430. updateBI = w.updateSVG;
  2431. break;
  2432. }
  2433. case 2: {
  2434. updateBO = w.updateSVG;
  2435. break;
  2436. }
  2437. }
  2438. }
  2439. }
  2440. catch (ex) {
  2441. }
  2442.  
  2443. if (i < 0) {
  2444. svgReady = 1;
  2445. updateCD(nfmarks, abc);
  2446. updateBI(irates, abc);
  2447. updateBO(orates, abc);
  2448. }
  2449. else if (--svgReady > -5)
  2450. setTimeout(checkSVG, 500);
  2451. }
  2452.  
  2453. function _ethstates(port) {
  2454. var fn, state1, state2;
  2455.  
  2456. if (port == null) {
  2457. fn = 'eth_off';
  2458. state2 = 'NOSUPPORT';
  2459. }
  2460. else if (port == 'DOWN') {
  2461. fn = 'eth_off';
  2462. state2 = port.replace('DOWN','Unplugged');
  2463. }
  2464. else if (port == '1000FD') {
  2465. fn = 'eth_1000_fd';
  2466. state1 = port.replace('HD','Mbps Half');
  2467. state2 = state1.replace('FD','Mbps Full');
  2468. }
  2469. else if (port == '1000HD') {
  2470. fn = 'eth_1000_hd';
  2471. state1 = port.replace('HD','Mbps Half');
  2472. state2 = state1.replace('FD','Mbps Full');
  2473. }
  2474. else if (port == '100FD') {
  2475. fn = 'eth_100_fd';
  2476. state1 = port.replace('HD','Mbps Half');
  2477. state2 = state1.replace('FD','Mbps Full');
  2478. }
  2479. else if (port == '100HD') {
  2480. fn = 'eth_100_hd';
  2481. state1 = port.replace('HD','Mbps Half');
  2482. state2 = state1.replace('FD','Mbps Full');
  2483. }
  2484. else if (port == '10FD') {
  2485. fn = 'eth_10_fd';
  2486. state1 = port.replace('HD','Mbps Half');
  2487. state2 = state1.replace('FD','Mbps Full');
  2488. }
  2489. else if (port == '10HD') {
  2490. fn = 'eth_10_hd';
  2491. state1 = port.replace('HD','Mbps Half');
  2492. state2 = state1.replace('FD','Mbps Full');
  2493. }
  2494. else {
  2495. fn = 'eth_1000_fd';
  2496. state2 = 'AUTO';
  2497. }
  2498.  
  2499. return [fn, state2];
  2500. }
  2501.  
  2502. function myName() {
  2503. var name, i;
  2504.  
  2505. name = document.location.pathname;
  2506. name = name.replace(/\\/g, '/'); /* IE local testing */
  2507. if ((i = name.lastIndexOf('/')) != -1) name = name.substring(i + 1, name.length);
  2508. if (name == '') name = 'status-overview.asp';
  2509. return name;
  2510. }
  2511.  
  2512. function navi() {
  2513. var menu = [
  2514. ['Status', 'status', 0, [
  2515. ['Overview', 'overview.asp'],
  2516. ['Device List', 'devices.asp'],
  2517. ['Web Usage', 'webmon.asp'],
  2518. ['Logs', 'log.asp'] ] ],
  2519. ['Bandwidth', 'bwm', 0, [
  2520. ['Real-Time', 'realtime.asp'],
  2521. ['Last 24 Hours', '24.asp'],
  2522. ['Daily', 'daily.asp'],
  2523. ['Weekly', 'weekly.asp'],
  2524. ['Monthly', 'monthly.asp']
  2525. ] ],
  2526. ['IP Traffic', 'ipt', 0, [
  2527. ['Real-Time', 'realtime.asp'],
  2528. ['Last 24 Hours', '24.asp'],
  2529. ['View Graphs', 'graphs.asp'],
  2530. ['Transfer Rates', 'details.asp'],
  2531. ['Daily', 'daily.asp'],
  2532. ['Monthly', 'monthly.asp']
  2533. ] ],
  2534. ['Tools', 'tools', 0, [
  2535. ['Ping', 'ping.asp'],
  2536. ['Traceroute', 'trace.asp'],
  2537. ['System Commands', 'shell.asp'],
  2538. ['Wireless Survey', 'survey.asp'],
  2539. /* QRCODE-BEGIN */
  2540. ['WiFi QR Codes', 'qr.asp'],
  2541. /* QRCODE-END */
  2542. /* IPERF-BEGIN */
  2543. ['iPerf', 'iperf.asp'],
  2544. /* IPERF-END */
  2545. ['Wake on LAN', 'wol.asp'] ] ],
  2546. null,
  2547. ['Basic', 'basic', 0, [
  2548. ['Network', 'network.asp'],
  2549. /* IPV6-BEGIN */
  2550. ['IPv6', 'ipv6.asp'],
  2551. /* IPV6-END */
  2552. ['Identification', 'ident.asp'],
  2553. ['Time', 'time.asp'],
  2554. ['DDNS', 'ddns.asp'],
  2555. ['DHCP Reservation', 'static.asp'],
  2556. ['Wireless Filter', 'wfilter.asp'] ] ],
  2557. ['Advanced', 'advanced', 0, [
  2558. ['Conntrack/Netfilter', 'ctnf.asp'],
  2559. ['DHCP/DNS', 'dhcpdns.asp'],
  2560. ['Firewall', 'firewall.asp'],
  2561. /* HTTPS-BEGIN */
  2562. ['Adblock', 'adblock.asp'],
  2563. /* HTTPS-END */
  2564. ['MAC Address', 'mac.asp'],
  2565. ['Miscellaneous', 'misc.asp'],
  2566. ['Routing', 'routing.asp'],
  2567. ['MultiWAN Routing', 'pbr.asp'],
  2568. /* TOR-BEGIN */
  2569. ['TOR Project', 'tor.asp'],
  2570. /* TOR-END */
  2571. ['VLAN', 'vlan.asp'],
  2572. ['LAN Access', 'access.asp'],
  2573. ['Virtual Wireless', 'wlanvifs.asp'],
  2574. ['Wireless', 'wireless.asp'] ] ],
  2575. ['Port Forwarding', 'forward', 0, [
  2576. ['Basic', 'basic.asp'],
  2577. /* IPV6-BEGIN */
  2578. ['Basic IPv6', 'basic-ipv6.asp'],
  2579. /* IPV6-END */
  2580. ['DMZ', 'dmz.asp'],
  2581. ['Triggered', 'triggered.asp'],
  2582. ['UPnP/NAT-PMP', 'upnp.asp'] ] ],
  2583. ['Access Restriction', 'restrict.asp'],
  2584. ['QoS', 'qos', 0, [
  2585. ['Basic Settings', 'settings.asp'],
  2586. ['Classification', 'classify.asp'],
  2587. ['View Graphs', 'graphs.asp'],
  2588. ['View Details', 'detailed.asp'],
  2589. ['Transfer Rates', 'ctrate.asp']
  2590. ] ],
  2591. ['Bandwidth Limiter', 'bwlimit.asp'],
  2592. null,
  2593. /* NOCAT-BEGIN */
  2594. ['Captive Portal', 'splashd.asp'],
  2595. /* NOCAT-END */
  2596. /* NGINX-BEGIN */
  2597. ['Web Server', 'web', 0, [
  2598. ['Nginx & PHP', 'nginx.asp'],
  2599. ['MySQL Server', 'mysql.asp']
  2600. ] ],
  2601. /* NGINX-END */
  2602. /* USB-BEGIN */
  2603. ['USB and NAS', 'nas', 0, [
  2604. ['USB Support', 'usb.asp']
  2605. /* FTP-BEGIN */
  2606. ,['FTP Server', 'ftp.asp']
  2607. /* FTP-END */
  2608. /* SAMBA-BEGIN */
  2609. ,['File Sharing', 'samba.asp']
  2610. /* SAMBA-END */
  2611. /* MEDIA-SRV-BEGIN */
  2612. ,['Media Server', 'media.asp']
  2613. /* MEDIA-SRV-END */
  2614. /* UPS-BEGIN */
  2615. ,['UPS Monitor', 'ups.asp']
  2616. /* UPS-END */
  2617. /* BT-BEGIN */
  2618. ,['BitTorrent Client', 'bittorrent.asp']
  2619. /* BT-END */
  2620. ] ],
  2621. /* USB-END */
  2622. /* VPN-BEGIN */
  2623. ['VPN Tunneling', 'vpn', 0, [
  2624. /* OPENVPN-BEGIN */
  2625. ['OpenVPN Server', 'server.asp'],
  2626. ['OpenVPN Client', 'client.asp'],
  2627. /* OPENVPN-END */
  2628. /* PPTPD-BEGIN */
  2629. ['PPTP Server', 'pptp-server.asp'],
  2630. ['PPTP Online', 'pptp-online.asp'],
  2631. ['PPTP Client', 'pptp.asp']
  2632. /* PPTPD-END */
  2633. /* TINC-BEGIN */
  2634. ,['Tinc Daemon', 'tinc.asp']
  2635. /* TINC-END */
  2636. ] ],
  2637. /* VPN-END */
  2638. null,
  2639. ['Administration', 'admin', 0, [
  2640. ['Admin Access', 'access.asp'],
  2641. ['TomatoAnon', 'tomatoanon.asp'],
  2642. ['Bandwidth Monitoring', 'bwm.asp'],
  2643. ['IP Traffic Monitoring', 'iptraffic.asp'],
  2644. ['Buttons/LED', 'buttons.asp'],
  2645. /* CIFS-BEGIN */
  2646. ['CIFS Client', 'cifs.asp'],
  2647. /* CIFS-END */
  2648. ['Configuration', 'config.asp'],
  2649. ['Debugging', 'debug.asp'],
  2650. /* JFFS2-BEGIN */
  2651. ['JFFS', 'jffs2.asp'],
  2652. /* JFFS2-END */
  2653. /* NFS-BEGIN */
  2654. ['NFS Server', 'nfs.asp'],
  2655. /* NFS-END */
  2656. /* SNMP-BEGIN */
  2657. ['SNMP', 'snmp.asp'],
  2658. /* SNMP-END */
  2659. ['Logging', 'log.asp'],
  2660. ['Scheduler', 'sched.asp'],
  2661. ['Scripts', 'scripts.asp'],
  2662. ['Upgrade', 'upgrade.asp'] ] ],
  2663. null,
  2664. ['About', 'about.asp'],
  2665. ['Reboot...', 'javascript:reboot()'],
  2666. ['Halt...', 'javascript:halt()'],
  2667. ['Logout', 'javascript:logout()']
  2668. ];
  2669. var name, base;
  2670. var i, j;
  2671. var buf = [];
  2672. var sm;
  2673. var a, b, c;
  2674. var on1;
  2675. var cexp = get_config('web_mx', '').toLowerCase();
  2676.  
  2677. name = myName();
  2678. if (name == 'restrict-edit.asp') name = 'restrict.asp';
  2679. if ((i = name.indexOf('-')) != -1) {
  2680. base = name.substring(0, i);
  2681. name = name.substring(i + 1, name.length);
  2682. }
  2683. else base = '';
  2684.  
  2685. for (i = 0; i < menu.length; ++i) {
  2686. var m = menu[i];
  2687. if (!m) {
  2688. buf.push("<br>");
  2689. continue;
  2690. }
  2691. if (m.length == 2) {
  2692. buf.push('<a href="' + m[1] + '" class="indent1' + (((base == '') && (name == m[1])) ? ' active' : '') + '">' + m[0] + '</a>');
  2693. }
  2694. else {
  2695. if (base == m[1]) {
  2696. b = name;
  2697. }
  2698. else {
  2699. a = cookie.get('menu_' + m[1]);
  2700. b = m[3][0][1];
  2701. for (j = 0; j < m[3].length; ++j) {
  2702. if (m[3][j][1] == a) {
  2703. b = a;
  2704. break;
  2705. }
  2706. }
  2707. }
  2708. a = m[1] + '-' + b;
  2709. if (a == 'status-overview.asp') a = '/';
  2710. on1 = (base == m[1]);
  2711. buf.push('<a href="' + a + '" class="indent1' + (on1 ? ' active' : '') + '">' + m[0] + '</a>');
  2712. if ((!on1) && (m[2] == 0) && (cexp.indexOf(m[1]) == -1)) continue;
  2713.  
  2714. for (j = 0; j < m[3].length; ++j) {
  2715. sm = m[3][j];
  2716. a = m[1] + '-' + sm[1];
  2717. if (a == 'status-overview.asp') a = '/';
  2718. buf.push('<a href="' + a + '" class="indent2' + (((on1) && (name == sm[1])) ? ' active' : '') + '">' + sm[0] + '</a>');
  2719. }
  2720. }
  2721. }
  2722. document.write(buf.join(''));
  2723.  
  2724. if (base.length) {
  2725. if ((base == 'qos') && (name == 'detailed.asp')) name = 'view.asp';
  2726. cookie.set('menu_' + base, name);
  2727. }
  2728. }
  2729.  
  2730. function createFieldTable(flags, desc) {
  2731. var common, i, n, name, id, fields, placeholder, onclick, f, a, buf2, id1, tr;
  2732. var buf = [];
  2733.  
  2734. if (flags.indexOf('noopen') == -1) buf.push('<table class="fields">');
  2735. for (var desci = 0; desci < desc.length; ++desci) {
  2736. var v = desc[desci];
  2737.  
  2738. if (!v) {
  2739. buf.push('<tr><td colspan="2" class="spacer">&nbsp;</td></tr>');
  2740. continue;
  2741. }
  2742.  
  2743. if (v.ignore) continue;
  2744.  
  2745. buf.push('<tr');
  2746. if (v.rid) buf.push(' id="'+v.rid+'"');
  2747. if (v.hidden) buf.push(' style="display:none"');
  2748. buf.push('>');
  2749.  
  2750. if (v.text) {
  2751. if (v.title)
  2752. buf.push('<td class="title indent'+(v.indent || 1)+'">'+v.title+'</td><td class="content">'+v.text+'</td></tr>');
  2753. else
  2754. buf.push('<td colspan="2">'+v.text+'</td></tr>');
  2755.  
  2756. continue;
  2757. }
  2758.  
  2759. id1 = '';
  2760. buf2 = [];
  2761. buf2.push('<td class="content">');
  2762.  
  2763. if (v.multi)
  2764. fields = v.multi;
  2765. else
  2766. fields = [v];
  2767.  
  2768. for (n = 0; n < fields.length; ++n) {
  2769. f = fields[n];
  2770. if (f.prefix) buf2.push(f.prefix);
  2771.  
  2772. if ((f.type == 'radio') && (!f.id))
  2773. id = '_'+f.name+'_'+i;
  2774. else
  2775. id = (f.id ? f.id : ('_'+f.name));
  2776.  
  2777. if (id1 == '') id1 = id;
  2778.  
  2779. common = ' onchange="verifyFields(this, 1)" id="'+id+'"';
  2780. if (f.attrib) common += ' '+f.attrib;
  2781. name = f.name ? (' name="'+f.name+'"') : '';
  2782. placeholder = f.placeholder ? (' placeholder="'+f.placeholder+'"') : '';
  2783. onclick = f.onclick ? (';'+f.onclick+'') : '';
  2784. console.log(onclick);
  2785.  
  2786. switch (f.type) {
  2787. case 'checkbox':
  2788. buf2.push('<input type="checkbox"'+name+(f.value ? ' checked="checked"' : '')+' onclick="verifyFields(this, 1)'+onclick+'"' +common+'>');
  2789. break;
  2790. case 'radio':
  2791. buf2.push('<input type="radio"'+name+(f.value ? ' checked="checked"' : '')+' onclick="verifyFields(this, 1)'+onclick+'"' +common+'>');
  2792. break;
  2793. case 'password':
  2794. if (f.peekaboo) {
  2795. switch (get_config('web_pb', '1')) {
  2796. case '0':
  2797. f.type = 'text';
  2798. case '2':
  2799. f.peekaboo = 0;
  2800. break;
  2801. }
  2802. }
  2803. if (f.type == 'password') {
  2804. common += ' autocomplete="off"';
  2805. if (f.peekaboo) common += ' onfocus="peekaboo(\''+id+'\',1)"';
  2806. }
  2807. /* drop */
  2808. case 'text':
  2809. buf2.push('<input type="'+f.type+'"'+name+placeholder+' value="'+escapeHTML(UT(f.value))+'" maxlength='+f.maxlen+(f.size ? (' size='+f.size) : '')+common+'>');
  2810. break;
  2811. case 'clear':
  2812. s += '';
  2813. break;
  2814. case 'select':
  2815. buf2.push('<select'+name+common+'>');
  2816. for (i = 0; i < f.options.length; ++i) {
  2817. a = f.options[i];
  2818. if (a.length == 1) a.push(a[0]);
  2819. buf2.push('<option value="'+a[0]+'"'+((a[0] == f.value) ? ' selected="selected"' : '')+'>'+a[1]+'</option>');
  2820. }
  2821. buf2.push('</select>');
  2822. break;
  2823. case 'textarea':
  2824. buf2.push('<textarea'+name+common+placeholder+(f.wrap ? (' style="white-space:'+f.wrap+';overflow-wrap:normal;overflow-x:scroll"') : '')+'>'+escapeHTML(UT(f.value))+'</textarea>');
  2825. break;
  2826. default:
  2827. if (f.custom) buf2.push(f.custom);
  2828. break;
  2829. }
  2830. if (f.suffix) buf2.push(f.suffix);
  2831. }
  2832. buf2.push('</td>');
  2833.  
  2834. buf.push('<td class="title indent'+(v.indent ? v.indent : 1)+'">');
  2835. if (id1 != '')
  2836. buf.push('<label'+((id && id != '_undefined' ) ? ' for="'+id+'"' : '')+'>'+(v.title ? v.title : '&nbsp;')+'</label></td>');
  2837. else
  2838. buf.push(+v.title+'</td>');
  2839.  
  2840. buf.push(buf2.join(''));
  2841. buf.push('</tr>');
  2842. }
  2843. if ((!flags) || (flags.indexOf('noclose') == -1)) buf.push('</table>');
  2844. document.write(buf.join(''));
  2845. }
  2846.  
  2847. function peekaboo(id, show) {
  2848. try {
  2849. var o = document.createElement('INPUT');
  2850. var e = E(id);
  2851. var name = e.name;
  2852. o.type = show ? 'text' : 'password';
  2853. o.value = e.value;
  2854. o.size = e.size;
  2855. o.maxLength = e.maxLength;
  2856. o.autocomplete = e.autocomplete;
  2857. o.title = e.title;
  2858. o.disabled = e.disabled;
  2859. o.onchange = e.onchange;
  2860. e.parentNode.replaceChild(o, e);
  2861. e = null;
  2862. o.id = id;
  2863. o.name = name;
  2864.  
  2865. if (show) {
  2866. o.onblur = function(ev) { setTimeout('peekaboo("' + this.id + '", 0)', 0) };
  2867. setTimeout('try { E("' + id + '").focus() } catch (ex) { }', 0)
  2868. }
  2869. else {
  2870. o.onfocus = function(ev) { peekaboo(this.id, 1); };
  2871. }
  2872. }
  2873. catch (ex) {
  2874. /* alert(ex); */
  2875. }
  2876.  
  2877. /* REMOVE-BEGIN
  2878. notes:
  2879. - e.type= doesn't work in IE, ok in FF
  2880. - may mess keyboard tabing (bad: IE; ok: FF, Opera)... setTimeout() delay seems to help a little.
  2881. REMOVE-END */
  2882. }
  2883.  
  2884. // -----------------------------------------------------------------------------
  2885.  
  2886. function isLocal() {
  2887. return location.href.search('file://') == 0;
  2888. }
  2889.  
  2890. function reloadPage() {
  2891. document.location.reload(1);
  2892. }
  2893.  
  2894. function reboot() {
  2895. if (confirm("Reboot?")) form.submitHidden('tomato.cgi', { _reboot: 1, _commit: 0, _nvset: 0 });
  2896. }
  2897.  
  2898. function halt() {
  2899. if (!confirm("Halt?")) return;
  2900. if (confirm("Are you really sure you want to halt the router??\nThis will require a manual power cycle to boot again.")) form.submitHidden('shutdown.cgi', { });
  2901. }
  2902.  
  2903. function logout() {
  2904. form.submitHidden('logout.asp', { });
  2905. }
  2906.  
  2907. function toggleVisibility(where, whichone) {
  2908. if (E('sesdiv_' + whichone).style.display != 'none') {
  2909. E('sesdiv_' + whichone).style.display = 'none';
  2910. E('sesdiv_' + whichone + '_showhide').innerHTML = '(Show)';
  2911. cookie.set(where + '_' + whichone + '_vis', 0);
  2912. }
  2913. else {
  2914. E('sesdiv_' + whichone).style.display = 'block';
  2915. E('sesdiv_' + whichone + '_showhide').innerHTML = '(Hide)';
  2916. cookie.set(where + '_' + whichone + '_vis', 1);
  2917. }
  2918. }
  2919.  
  2920. function spinOUI(x, which) {
  2921. E(which).style.display = (x ? 'inline-block' : 'none');
  2922. if (!x)
  2923. cmd = null;
  2924. }
  2925.  
  2926. function searchOUI(n, i) {
  2927. if (cmd)
  2928. return;
  2929.  
  2930. spinOUI(1, 'gW_'+i);
  2931.  
  2932. cmd = new XmlHttp();
  2933. cmd.onCompleted = function(text, xml) {
  2934. eval(text);
  2935. displayOUI(i);
  2936. }
  2937. cmd.onError = function(x) {
  2938. cmdresult = 'ERROR: '+x;
  2939. displayOUI(i);
  2940. }
  2941.  
  2942. var commands = '/usr/bin/wget -T 6 -q http://api.macvendors.com/'+n+' -O /tmp/oui.txt \n /bin/cat /tmp/oui.txt';
  2943. cmd.post('shell.cgi', 'action=execute&command='+escapeCGI(commands.replace(/\r/g, '')));
  2944. }
  2945.  
  2946. function displayOUI(i) {
  2947. spinOUI(0, 'gW_'+i);
  2948. if (cmdresult.indexOf('bad address') != -1)
  2949. cmdresult = 'No Internet! Check your Network/DNS settings!';
  2950. else if (cmdresult.indexOf('Not Found') == -1)
  2951. cmdresult = 'Manufacturer: \n'+cmdresult;
  2952. else
  2953. cmdresult = 'Manufacturer not found!';
  2954.  
  2955. alert(cmdresult);
  2956. cmdresult = '';
  2957. }
  2958.  
  2959. function wikiLink() {
  2960. const url = "https://wiki.freshtomato.org/doku.php"
  2961. var page = myName();
  2962. if (page)
  2963. page = page.replace(/\.asp$/, "");
  2964. else
  2965. page = 'status-overview';
  2966.  
  2967. var res = '<a href=\"'+url+'/'+page+'\" target=\"_blank\" rel=\"noopener noreferrer\">Wiki</a>';
  2968. document.write(res);
  2969. }
  2970.  
  2971. var up = new TomatoRefresh('isup.jsz', '', 5);
  2972. up.refresh = function(text) {
  2973. isup = {};
  2974. try {
  2975. eval(text);
  2976. }
  2977. catch (ex) {
  2978. //alert('ex='+ex);
  2979. isup = {};
  2980. }
  2981. if (typeof show === 'function') show();
  2982. }
  2983.  
  2984. // -----------------------------------------------------------------------------
  2985.  
  2986. // ---- events handler
  2987.  
  2988. if (typeof document.getElementsByClassName != 'function') { /* IE */
  2989. document.getElementsByClassName = function(cl) {
  2990. var retnode = new Array(), patt = new RegExp("(^|\\\\s)" + cl + "(\\\\s|$)"), els = this.getElementsByTagName('*');
  2991. for (i = 0, j = 0; i < els.length; i++) {
  2992. if (patt.test(els[i].className)) {
  2993. retnode[j] = els[i];
  2994. j++;
  2995. }
  2996. }
  2997. return retnode;
  2998. };
  2999. }
  3000.  
  3001. function addEvent(obj, type, fn) {
  3002. if (obj.addEventListener) {
  3003. obj.addEventListener(type, fn, false);
  3004. EventCache.add(obj, type, fn);
  3005. }
  3006. else if (obj.attachEvent) {
  3007. obj['e' + type + fn] = fn;
  3008. obj[type + fn] = function() { obj['e' + type + fn](window.event); }
  3009. obj.attachEvent('on' + type, obj[type + fn]);
  3010. EventCache.add(obj, type, fn);
  3011. }
  3012. else {
  3013. obj['on' + type] = obj['e' + type + fn];
  3014. }
  3015. }
  3016.  
  3017. var EventCache = function() {
  3018. var listEvents = [];
  3019. return {
  3020. listEvents : listEvents,
  3021. add : function(node, sEventName, fHandler) {
  3022. listEvents.push(arguments);
  3023. },
  3024. flush : function() {
  3025. var i, item;
  3026. for (i = listEvents.length - 1; i >= 0; i = i - 1) {
  3027. item = listEvents[i];
  3028. if (item[0].removeEventListener) {
  3029. item[0].removeEventListener(item[1], item[2], false);
  3030. };
  3031. if (item[1].substring(0, 2) != 'on') {
  3032. item[1] = 'on' + item[1];
  3033. };
  3034. if (item[0].detachEvent) {
  3035. item[0].detachEvent(item[1], item[2]);
  3036. };
  3037. item[0][item[1]] = null;
  3038. };
  3039. }
  3040. };
  3041. }();
  3042.  
  3043. addEvent(window, 'unload', EventCache.flush);
  3044. function cancelDefaultAction(e) {
  3045. var evt = e ? e : window.event;
  3046. if (evt.preventDefault) evt.preventDefault();
  3047. evt.returnValue = false;
  3048. return false;
  3049. }
  3050.  
  3051. function eventHandler() {
  3052. var elements = document.getElementsByClassName('new_window');
  3053. for (var i = 0; i < elements.length; i++) if (elements[i].nodeName.toLowerCase()==='a')
  3054. addEvent(elements[i], 'click', function(e) { cancelDefaultAction(e); window.open(this,'_blank'); } );
  3055. }
Add Comment
Please, Sign In to add comment