/* * This program is copyright © 2008-2011 Eric Bishop and is distributed under the terms of the GNU GPL * version 2.0 with a special clarification/exception that permits adapting the program to * configure proprietary "back end" software provided that all modifications to the web interface * itself remain covered by the GPL. * See http://gargoyle-router.com/faq.html#qfoss for more information */ var UI=new Object(); //part of i18n var TiZ=new Object(); //i18n timezones var TSort_Classes = new Array ('odd', 'even'); // table sorting zebra row support var menuState = []; //nav Menu State variable var navTimer; //timeout for restoring menu // Abbreviation. function byId(id, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; return controlDocument.getElementById(id); } // Escape HTML using DOM API. function escapeHTML(html) { let container = document.createElement("div"); container.textContent = html; return container.innerHTML; } // Automatically adjust height of element to fit its content without scrollbars. function autoHeight(element) { element.style.height = ""; let computed = window.getComputedStyle(element); let height = element.scrollHeight + parseInt(computed.getPropertyValue("border-top-width")) + parseInt(computed.getPropertyValue("padding-top")) + parseInt(computed.getPropertyValue("padding-bottom")) + parseInt(computed.getPropertyValue("border-bottom-width")); element.style.height = height + "px"; } window.onresize = function onresize() { //in case this gets called while initializing page, you may get error if element isnt defined, //so use a try/catch try { if(document.getElementById("darken").style.display == "block") { setControlsEnabled(false, document.getElementById("wait_msg").style.display == "block"); } } catch(e){} } // should be called by hooks // main page code can just use regular resetData() function // which should get called first function addLoadFunction(func) { var old_load = window.onload; window.onload = (typeof window.onload != 'function') ? func : function() { old_load() ; func() ; } } function setControlsEnabled(enabled, showWaitMessage, waitText) { var dark = document.getElementById("darken"); var msg = document.getElementById("wait_msg"); document.getElementById("wait_txt").firstChild.data = UI.waitText; if (!enabled) { var totalHeight="100%"; var totalWidth="100%"; var heightFromDoc=0; var widthFromDoc=0; if(document.body.parentNode.scrollHeight) { heightFromDoc = heightFromDoc >= document.body.parentNode.scrollHeight ? heightFromDoc : document.body.parentNode.scrollHeight } if(document.body.scrollHeight) { heightFromDoc = heightFromDoc >= document.body.scrollHeight ? heightFromDoc : document.body.scrollHeight } if(document.height) { heightFromDoc = heightFromDoc >= document.height ? heightFromDoc : document.height } totalHeight = heightFromDoc > 0 ? heightFromDoc + "px" : totalHeight if(document.body.parentNode.scrollWidth) { widthFromDoc = widthFromDoc >= document.body.parentNode.scrollWidth ? widthFromDoc : document.body.parentNode.scrollWidth } if(document.body.scrollWidth) { widthFromDoc = widthFromDoc >= document.body.scrollWidth ? widthFromDoc : document.body.scrollWidth } if(document.width) { widthFromDoc = widthFromDoc >= document.width ? widthFromDoc : document.width } totalWidth = widthFromDoc > 0 ? widthFromDoc + "px" : totalWidth var viewportHeight; var vewportWidth; if(self.innerHeight) { viewportHeight = window.innerHeight; viewportWidth = window.innerWidth; } else if(document.documentElement && document.documentElement.clientHeight) { viewportHeight = document.documentElement.clientHeight; viewportWidth = document.documentElement.clientWidth; } else if(document.body) { viewportHeight = document.body.clientHeight; viewportWidth = document.body.clientWidth; } var leftOffset = Math.floor((viewportWidth-300)/2); var topOffset = Math.floor((viewportHeight-150)/2); var is_ie = false; if(document.all) { is_ie = true; } if(is_ie) { var di = document.getElementById("d_iframe"); di.style.display="block"; di.style.width=totalWidth; di.style.height=totalHeight; var dm = document.getElementById("m_iframe"); dm.style.display="block"; dm.style.width="300px"; dm.style.height="150px"; msg.style.position="absolute"; topOffset = topOffset + document.documentElement.scrollTop; leftOffset = leftOffset + document.documentElement.scrollLeft; } dark.style.height=totalHeight; dark.style.width=totalWidth; msg.style.left = leftOffset >= 0 ? leftOffset+"px" : "0px"; msg.style.top = topOffset >=0 ? topOffset+"px" : "0px"; dark.style.display="block"; if(showWaitMessage) { msg.style.display= "block"; if(waitText != null) { document.getElementById("wait_txt").firstChild.data = waitText; } } } else { dark.style.display="none"; msg.style.display= "none"; } //let's be sneaky -- instead of adding setBrowserTimeCookie() to the saveChanges() function on every page //just add it to this function which almost always gets called just before we set parameters //This covers all instances not taken care of by the runAjax() function, e.g. when submitting a form setBrowserTimeCookie(); } function setBrowserTimeCookie() { var browserSecondsUtc = Math.floor( ( new Date() ).getTime() / 1000 ); document.cookie="browser_time=" +browserSecondsUtc + "; path=/"; //don't bother with expiration -- who cares when the cookie was set? It just contains the current time, which the browser already knows } function getRequestObj() { var req; try { // standards compliant browsers req = new XMLHttpRequest(); } catch (ex) { // MicroShit Browsers try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch (ex) { try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch (ex) { // Browser is not Ajax compliant return false; } } } return req; } function runAjax(method, url, params, stateChangeFunction) { //let's be sneaky -- instead of adding setBrowserTimeCookie() to the saveChanges() function on every page //add it to this function, which gets run on every ajax call. This covers all instances not taken care of //by the setControlsEnabled() function setBrowserTimeCookie(); var req = getRequestObj(); if(req) { req.onreadystatechange = function() { stateChangeFunction(req); } if(method == "POST") { //for some reason we need at least one character of data, so use a space if params == null params = (params == null) ? " " : params; req.open("POST", url, true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //req.setRequestHeader("Content-length", params.length); //req.setRequestHeader("Connection", "close"); req.send(params); } else if(method == "GET") { req.open("GET", url + "?" + params, true); req.send(null); } } return req; } function execute(cmd) { var commands = cmd.join("\n"); var param = getParameterDefinition("commands", commands) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); setControlsEnabled(false, true, UI.WaitSettings); var stateChangeFunction = function(req) { if(req.readyState == 4) { setControlsEnabled(true); window.location.href=window.location.href; } } runAjax("POST", "utility/run_commands.sh", param, stateChangeFunction); } // The way we store keys is massively inefficient, but // there are generally few enough keys defined that // the O(N) time we're using doesn't impact performance. // // This implementation is necessary so we can control order // of sections, i.e. sections will be added in the order // they are defined with set method function UCIContainer() { this.keys = new Array(); this.values = new Array(); this.listOptions = new Array(); this.createListOption = function(pkg,section,option,destroy_existing_nonlist) { destroy_existing_nonlist = destroy_existing_nonlist == null ? true : false; var list_key = pkg + "\." + section + "\." + option; if( this.listOptions[ list_key ] != null ) { return; } this.listOptions[ list_key ] = 1; if( this.values[list_key] != null ) { var old = this.values[list_key]; this.values[list_key] = (!destroy_existing_nonlist) && old != null ? [old] : [] ; } else { this.keys.push(list_key); this.values[list_key] = []; } } this.set = function(pkg, section, option, value, preserveExistingListValues) { preserveExistingListValues = preserveExistingListValues == null ? false : preserveExistingListValues; var next_key = pkg + "\." + section; if(option != null && option != "" ) { next_key = next_key + "\." + option; } if(this.values[next_key] != null) { if (this.listOptions[ next_key ] != null) { var set = this.values[next_key]; while(set.length > 0 && (!preserveExistingListValues)) { set.pop(); } if( value instanceof Array ) { var vi; for(vi=0; vi 0) { var nextKey = this.keys.shift(); if(nextKey != removeKey){ newKeys.push(nextKey); } } this.keys = newKeys; } else { value = '' } return value; } this.removeSection = function(pkg, section) { removeKeys = new Array(); sectionDefined = false; for (keyIndex in this.keys) { key = this.keys[keyIndex]; testExp = new RegExp(pkg + "\\." + section + "\\."); if(key.match(testExp)) { var splitKey = key.split("\."); removeKeys.push(splitKey[2]); } if(key == pkg + "." + section) { sectionDefined = true; } } for (rkIndex in removeKeys) { this.remove(pkg, section, removeKeys[rkIndex]); } if(sectionDefined) { this.remove(pkg, section, ""); } } this.clone = function() { var copy = new UCIContainer(); var keyIndex = 0; for(keyIndex = 0; keyIndex < this.keys.length; keyIndex++) { var key = this.keys[keyIndex]; var val = this.values[key] if( this.listOptions[ key ] != null ) { copy.listOptions[ key ] = 1; } var splitKey = key.match(/^([^\.]+)\.([^\.]+)\.([^\.]+)$/); if(splitKey == null) { splitKey = key.match(/^([^\.]+)\.([^\.]+)$/); if(splitKey != null) { splitKey.push(""); } else { //should never get here -- if problems put debugging code here //val = val; // good enough for a breakpoint to be set. } } copy.set(splitKey[1], splitKey[2], splitKey[3], val, true); } return copy; } this.print = function() { var str=""; var keyIndex=0; for(keyIndex=0; keyIndex < this.keys.length; keyIndex++) { var key = this.keys[keyIndex] if(this.values[key] instanceof Array ) { str=str+ "\n" + key + " = \"" + this.values[key].join(",") + "\""; } else { str=str+ "\n" + key + " = \"" + this.values[key] + "\""; } } return str; } // sections are printed in the same order they were added (with the set method) this.getScriptCommands = function(oldSettings) { var commandArray = new Array(); var listsWithoutUpdates = []; var keyIndex=0; for(keyIndex=0; keyIndex < oldSettings.keys.length; keyIndex++) { var key = oldSettings.keys[keyIndex]; var oldValue = oldSettings.values[key]; var newValue = this.values[key]; if( (oldValue instanceof Array && !(newValue instanceof Array)) || (newValue instanceof Array && !(oldValue instanceof Array)) ) { commandArray.push( "uci del " + key); } else if (oldValue instanceof Array && newValue instanceof Array) { var matches = oldValue.length == newValue.length; if(matches) { var matchIndex; for(matchIndex=0; matches && matchIndex < oldValue.length; matchIndex++) { matches = oldValue[matchIndex] == newValue[matchIndex] ? true : false } } if(matches) { listsWithoutUpdates[key] = 1 } else { commandArray.push( "uci del " + key); } } else if((newValue == null || newValue == '') && (oldValue != null && oldValue !='')) { commandArray.push( "uci del " + key); } } for(keyIndex=0; keyIndex < this.keys.length; keyIndex++) { var key = this.keys[keyIndex]; var oldValue = oldSettings.values[key]; var newValue = this.values[key]; try { if( (oldValue instanceof Array) || (newValue instanceof Array) ) { if(newValue instanceof Array) { if(listsWithoutUpdates[key] == null) { var vi; for(vi=0; vi< newValue.length ; vi++) { var nv = "" + newValue[vi] + ""; commandArray.push( "uci add_list " + key + "=\'" + nv.replace(/'/g, "'\\''") + "\'" ); } } } else { newValue = "" + newValue + "" commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/g, "'\\''") + "\'" ); } } else if(oldValue != newValue && (newValue != null && newValue !='')) { newValue = "" + newValue + "" commandArray.push( "uci set " + key + "=\'" + newValue.replace(/'/g, "'\\''") + "\'" ); } } catch(e) { alert("bad key = " + key + "\n"); } } commandArray.push("uci commit"); return commandArray.join("\n"); } } function getParameterDefinition(parameter, definition) { return(encodeURIComponent(parameter) + "=" + encodeURIComponent(definition)); } function removeStringFromArray(arr, str) { var arrIndex; var newArr = []; for(arrIndex=0;arrIndex 0) { var txt = textParts.shift() parentElement.appendChild(controlDocument.createTextNode(txt)); if(textParts.length > 0) { parentElement.appendChild(controlDocument.createElement('br')); } } } } function createInput(type, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; if(type == "button") { try { inp = controlDocument.createElement('button'); inp.type = type; } catch(e) { inp = controlDocument.createElement(''); } } else { try { inp = controlDocument.createElement('input'); inp.type = type; } catch(e) { inp = controlDocument.createElement(''); } } return inp; } function trueAndVisible(elementId, visibilityId) { return (document.getElementById(elementId).checked && document.getElementById(visibilityId).style.display != 'none'); } function getDhcpSection(uciData) { var allDhcpSections = uciData.getAllSections("dhcp"); var dhcpSection = allDhcpSections.length > 0 ? allDhcpSections[0] : "cfg1"; for(dsecIndex=0; dsecIndex < allDhcpSections.length; dsecIndex++) { if(uciData.get("dhcp", allDhcpSections[dsecIndex], "interface") == "lan") { dhcpSection = allDhcpSections[dsecIndex]; } } return dhcpSection; } function getWirelessMode(uciTest) { var deviceSections = uciTest.getAllSectionsOfType("wireless", "wifi-device"); var validDevices = []; var di; for(di=0; di < deviceSections.length; di++) { var disabled = uciTest.get("wireless", deviceSections[di], "disabled"); if(disabled == "0" || disabled == "") { validDevices[ deviceSections[di] ] = 1 } } var ap = ''; var other = ''; var ifSections = uciTest.getAllSectionsOfType("wireless", "wifi-iface"); var ifi; for(ifi=0; ifi < ifSections.length; ifi++) { var dev = uciTest.get("wireless", ifSections[ifi], "device"); if( validDevices[ dev ] == 1) { var mode = uciTest.get("wireless", ifSections[ifi], "mode"); ap = mode == "ap" ? mode : ap; other = mode == "ap" ? (uciTest.get("wireless", ifSections[ifi], "wds") ? "wds" : other) : mode; } } var p = ap != '' && other != '' ? '+' : ''; var wirelessMode = ap + p + other; var wirelessMode= wirelessMode == '' ? 'disabled' : wirelessMode; return wirelessMode; } function scrollUntilInView(element) { var bounding = element.getBoundingClientRect(); // Consider header of fixed position. var contentTop = document.getElementById("content").getBoundingClientRect().top; // Only scroll element if not already in view. if(bounding.top < contentTop || bounding.bottom > window.innerHeight) { // Scroll element just until its bottom is in view but only if its top is not truncated. var alignToTop = bounding.height > window.innerHeight - contentTop; try { // Try it smoothly. element.scrollIntoView({ behavior: "smooth", block: alignToTop ? "start" : "end" }); } catch(error) { // IE, Safari... element.scrollIntoView(alignToTop); } } } function setDescriptionVisibility(descriptionId, defaultDisplay, displayText, hideText) { defaultDisplay = (defaultDisplay == null) ? "inline" : defaultDisplay; displayText = (displayText == null) ? UI.MoreInfo : displayText; hideText = (hideText == null) ? UI.Hide : hideText; var ref = document.getElementById( descriptionId + "_ref" ); var txt = document.getElementById( descriptionId + "_txt" ); var box = document.getElementById( descriptionId ); var command = "uci set gargoyle.help." + descriptionId + "="; if(ref.firstChild.data == displayText) { ref.firstChild.data = hideText; txt.style.display = defaultDisplay; scrollUntilInView(box); command = command + "1\n"; } else { txt.style.display="none"; ref.firstChild.data = displayText; command = command + "0\n"; } command = command + "\nuci commit\n"; // we don't wait/notify user on completion so update seems instant var param = getParameterDefinition("commands", command) + "&" + getParameterDefinition("hash", document.cookie.replace(/^.*hash=/,"").replace(/[\t ;]+.*$/, "")); runAjax("POST", "utility/run_commands.sh", param, function(){ return 0; }); } function initializeDescriptionVisibility(testUci, descriptionId, defaultDisplay, displayText, hideText) { defaultDisplay = (defaultDisplay == null) ? "inline" : defaultDisplay; displayText = (displayText == null) ? UI.MoreInfo : displayText; hideText = (hideText == null) ? UI.Hide : hideText; var descLinkText = displayText; var descDisplay = "none"; var help = testUci.get("gargoyle", "help", descriptionId); if(help == "1") { descLinkText = hideText; descDisplay = defaultDisplay; } // don't try to re-initialize after we've already removed the help section if(help) { document.getElementById(descriptionId + "_ref").firstChild.data = descLinkText; document.getElementById(descriptionId + "_txt").style.display = descDisplay; } } function getSubnetRange(mask, ip) { //first we need to get size of subnet var splitMask = mask.split("."); if(splitMask.length != 4) { return []; } var masks = [ "255","254","252","248","240","224","192","128", "0" ]; var bits = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]; var subnetBits = 0; while(splitMask.length > 0) { var nextPart = splitMask.shift(); var nextBits = -1; for(testIndex=0 ; testIndex < 9 && nextBits < 0; testIndex++) { nextBits = masks[testIndex] == nextPart ? bits[testIndex] : nextBits; } if(nextBits < 0) { return []; } subnetBits = subnetBits + nextBits; } var subnetLength = Math.pow(2, subnetBits); var testIpEnd = parseInt( (ip.split("."))[3] ); var subnetStart = 0; while(subnetStart + subnetLength < testIpEnd) { subnetStart = subnetStart + subnetLength; } return [subnetStart, (subnetStart + subnetLength - 1) ]; } function rangeInSubnet(mask, ip, start, end) { var range = getSubnetRange(mask, ip); var subnetStart = range[0]; var subnetEnd = range[1]; if(subnetStart != null && subnetEnd != null) { if(subnetStart <= start && subnetEnd >= end) { return true; } } return false; } function parseIp(ip) { var ip = ip.split("."); return ((((((+ip[0])*256)+(+ip[1]))*256)+(+ip[2]))*256)+(+ip[3]); } function ipToStr(ip) { return ((ip>>>24)+'.'+(ip>>16 & 255)+'.'+(ip>>8 & 255)+'.'+(ip & 255)); } function parseCidr(ip) { var ip = ip.match(/(\d+)/g); var cidr = 0; for(var i in ip) { cidr += (((ip[i] >>> 0).toString(2)).match(/1/g) || []).length; } return cidr; } function ipInRange(ip, start, end) { var ip = parseIp(ip); return parseIp(start) <= ip && ip <= parseIp(end); } function ipInClassA(ip) { return ipInRange(ip, "0.0.0.0", "127.255.255.255"); } function ipInClassB(ip) { return ipInRange(ip, "128.0.0.0", "191.255.255.255"); } function ipInClassC(ip) { return ipInRange(ip, "192.0.0.0", "223.255.255.255"); } function ipInClassD(ip) { return ipInRange(ip, "224.0.0.0", "239.255.255.255"); } function ipInClassE(ip) { return ipInRange(ip, "240.0.0.0", "255.255.255.255"); } function ipInPrivateClassA(ip) { return ipInRange(ip, "10.0.0.0", "10.255.255.255"); } function ipInPrivateClassB(ip) { return ipInRange(ip, "172.16.0.0", "172.31.255.255"); } function ipInPrivateClassC(ip) { return ipInRange(ip, "192.168.0.0", "192.168.255.255"); } function ipInPrivate(ip) { return ipInPrivateClassA(ip) || ipInPrivateClassB(ip) || ipInPrivateClassC(ip); } function ipInLinkLocal(ip) { return ipInRange(ip, "169.254.0.0", "169.254.255.255"); } function ipInLocalhost(ip) { return ipInRange(ip, "127.0.0.0", "127.255.255.255"); } function proofreadFields(inputIds, labelIds, functions, validReturnCodes, visibilityIds, fieldDocument ) { fieldDocument = fieldDocument == null ? document : fieldDocument; var errorArray= new Array(); for (idIndex in inputIds) { isVisible = true; if(visibilityIds != null) { if(visibilityIds[idIndex] != null) { visibilityElement = fieldDocument.getElementById(visibilityIds[idIndex]); isVisible = visibilityElement.style.display == 'none' || visibilityElement.disabled == true ? false : true; } } if(isVisible) { input = fieldDocument.getElementById(inputIds[idIndex]); f = functions[idIndex]; proofreadText(input, f, validReturnCodes[idIndex]); if(f(input.value) != validReturnCodes[idIndex]) { labelStr = labelIds[idIndex] + ""; if( fieldDocument.getElementById(labelIds[idIndex]) != null) { labelStr = fieldDocument.getElementById(labelIds[idIndex]).firstChild.data; labelStr = labelStr.replace(/:/, ""); } else { alert("error in proofread: label with id " + labelIds[idIndex] + " is not defined"); } errorArray.push(UI.prfErr+" " + labelStr); } } } return errorArray; } function resetProofreadFields(inputIds) { for (var i = 0; i < inputIds.length; i++) { resetProofreadText(document.getElementById(inputIds[i])); } } function parseBytes(bytes, units, abbr, dDgt) { var parsed; units = ["KBytes","MBytes","GBytes","TBytes",UI.KBy,UI.MBy,UI.GBy,UI.TBy].indexOf(units) < 0 ? "mixed" : units; spcr = abbr==null||abbr==0 ? " " : ""; if( (units == "mixed" && bytes > 1024*1024*1024*1024) || ["TBytes",UI.TBy].indexOf(units) >= 0) { parsed = (bytes/(1024*1024*1024*1024)).toFixed(dDgt||3) + spcr + (abbr?UI.TB:UI.TBy); } else if( (units == "mixed" && bytes > 1024*1024*1024) || ["GBytes",UI.GBy].indexOf(units) >= 0) { parsed = (bytes/(1024*1024*1024)).toFixed(dDgt||3) + spcr + (abbr?UI.GB:UI.GBy); } else if( (units == "mixed" && bytes > 1024*1024) || ["MBytes",UI.MBy].indexOf(units) >= 0) { parsed = (bytes/(1024*1024)).toFixed(dDgt||3) + spcr + (abbr?UI.MB:UI.MBy); } else { parsed = (bytes/(1024)).toFixed(dDgt||3) + spcr + (abbr?UI.KB:UI.KBy); } return parsed; } function toBytes(val, unit) { var byteVal = val; if(unit == "KB") { byteVal = byteVal * 1024; } else if(unit == "MB") { byteVal = byteVal * 1024 * 1024; } else if(unit == "GB") { byteVal = byteVal * 1024 * 1024 * 1024; } else if(unit == "TB") { byteVal = byteVal * 1024 * 1024 * 1024 * 1024; } return byteVal; } function parseKbytesPerSecond(kbytes, units) { var parsed; units = units != "bytes/s" && units != "KBytes/s" && units != "MBytes/s" ? "mixed" : units; if( (units == "mixed" && kbytes > 1024) || units == "MBytes/s") { parsed = (kbytes/(1024)).toFixed(3) + " "+UI.MBs; } else { parsed = kbytes + " "+UI.KBs; } return parsed; } function truncateDecimal(dec) { result = "" + ((Math.floor(dec*1000))/1000); //make sure we have exactly three decimal places so //results line up properly in table presentation decMatch=result.match(/.*\.(.*)$/); if(decMatch == null) { result = result + ".000" } else { if(decMatch[1].length==1) { result = result + "00"; } else if(decMatch[1].length==2) { result = result + "0"; } } return result; } function enableAssociatedField(checkbox, associatedId, defaultValue, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; element=controlDocument.getElementById(associatedId); setElementEnabled(element, checkbox.checked, defaultValue); } function setElementEnabled(element, enabled, defaultValue) { if(enabled) { element.readonly=false; element.disabled=false; if(element.type == "text" || element.type == "textarea") { element.style.color=""; element.className="form-control" ; } else if(element.type == "select-one" || element.type == "select-multiple" || element.type == "select" ) { element.className="form-control"; } else if(element.type == "button") { element.classList.remove("disabled"); } } else { element.disabled=true; if(element.type == "text" || element.type == "textarea") { element.value=defaultValue; element.style.color="#AAAAAA"; element.className="form-control disabled"; } else if(element.type == "select-one" || element.type == "select-multiple" || element.type == "select" ) { setSelectedValue(element.id, defaultValue, element.ownerDocument); element.className="form-control disabled"; } else if(element.type == "button") { element.classList.add("disabled"); } else if(element.type == "file") { element.value=defaultValue; } } } function setElementReadOnly(element, readOnly) { if(readOnly) { element.disabled = false; } element.readOnly = readOnly; } function updateReadOnlyAssociate(associate, element) { var associate = document.getElementById(associate); if(associate.readOnly && !associate.disabled) { associate.value = element.value; associate.style.color = element.style.color; } } function getSelectedValue(selectId, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; if(controlDocument.getElementById(selectId) == null) { alert(UI.Err+": " + selectId + " "+UI.nex); return; } selectedIndex = controlDocument.getElementById(selectId).selectedIndex; selectedValue = ""; if(selectedIndex >= 0) { selectedValue= controlDocument.getElementById(selectId).options[ controlDocument.getElementById(selectId).selectedIndex ].value; } return selectedValue; } function getSelectedText(selectId, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; selectedIndex = controlDocument.getElementById(selectId).selectedIndex; selectedText = ""; if(selectedIndex >= 0) { selectedText= controlDocument.getElementById(selectId).options[ controlDocument.getElementById(selectId).selectedIndex ].text; } return selectedText; } function setSelectedValue(selectId, selection, controlDocument) { var controlDocument = controlDocument == null ? document : controlDocument; var selectElement = controlDocument.getElementById(selectId); if(selectElement == null){ alert(UI.Err+": " + selectId + " "+UI.nex); } var selectionFound = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!selectionFound); optionIndex++) { selectionFound = (selectElement.options[optionIndex].value == selection); if(selectionFound) { selectElement.selectedIndex = optionIndex; } } if(!selectionFound && selectElement.options.length > 0 && selectElement.selectedIndex < 0) { selectElement.selectedIndex = 0; } } function setSelectedText(selectId, selection, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; selectElement = controlDocument.getElementById(selectId); selectionFound = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!selectionFound); optionIndex++) { selectionFound = (selectElement.options[optionIndex].text == selection); if(selectionFound) { selectElement.selectedIndex = optionIndex; } } if(!selectionFound && selectElement.options.length > 0 && selectElement.selectedIndex < 0) { selectElement.selectedIndex = 0; } } function addOptionToSelectElement(selectId, optionText, optionValue, before, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; option = controlDocument.createElement("option"); option.text=optionText; option.value=optionValue; //FUCK M$ IE, FUCK IT UP THE ASS WITH A BASEBALL BAT. A BIG WOODEN ONE. WITH SPLINTERS. try { controlDocument.getElementById(selectId).add(option, before); } catch(e) { if(before == null) { controlDocument.getElementById(selectId).add(option); } else { controlDocument.getElementById(selectId).add(option, before.index); } } } function removeOptionFromSelectElement(selectId, optionText, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; selectElement = controlDocument.getElementById(selectId); selectionFound = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!selectionFound); optionIndex++) { selectionFound = (selectElement.options[optionIndex].text == optionText); if(selectionFound) { selectElement.remove(optionIndex); } } } function removeOptionFromSelectElementByValue(selectId, optionValue, controlDocument) { controlDocument = controlDocument == null ? document : controlDocument; selectElement = controlDocument.getElementById(selectId); selectionFound = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!selectionFound); optionIndex++) { selectionFound = (selectElement.options[optionIndex].value == optionValue); if(selectionFound) { selectElement.remove(optionIndex); } } } function removeAllOptionsFromSelectElement(selectElement) { while(selectElement.length > 0) { try { selectElement.remove(0); } catch(e){} } } function setAllowableSelections(selectId, allowableValues, allowableNames, controlDocument) { if(controlDocument == null) { controlDocument = document; } var selectElement = controlDocument.getElementById(selectId); if(allowableNames != null && allowableValues != null && selectElement != null) { var doReplace = true; if(allowableValues.length == selectElement.options.length) { doReplace = false; for(optionIndex = 0; optionIndex < selectElement.options.length && (!doReplace); optionIndex++) { doReplace = doReplace || (selectElement.options[optionIndex].text != allowableNames[optionIndex]) || (selectElement.options[optionIndex].value != allowableValues[optionIndex]) ; } } if(doReplace) { currentSelection=getSelectedValue(selectId, controlDocument); removeAllOptionsFromSelectElement(selectElement); for(addIndex=0; addIndex < allowableValues.length; addIndex++) { addOptionToSelectElement(selectId, allowableNames[addIndex], allowableValues[addIndex], null, controlDocument); } setSelectedValue(selectId, currentSelection, controlDocument); //restore original settings if still valid } } } function setSingleChild(container, child) { while(container.firstChild != null) { container.removeChild( container.firstChild); } container.appendChild(child); } function setVariableFromValue(params) { elementId = params[0]; visibilityId = params[1]; uci = params[2]; pkg = params[3]; section = params[4]; option = params[5]; setIfBlank = params[6]; var isVisible = true; if(visibilityId != null) { isVisible = document.getElementById(visibilityId).style.display == 'none' ? false : true; } if(isVisible == true) { value = document.getElementById(elementId).value; if(value != '' || setIfBlank == true) { uci.set(pkg, section, option, value); } } } function setVariableFromModifiedValue(params) { elementId = params[0]; visibilityId = params[1]; uci = params[2]; pkg = params[3]; section = params[4]; option = params[5]; setIfBlank = params[6]; modFunction = params[7]; isVisible = true; if(visibilityId != null) { isVisible = document.getElementById(visibilityId).style.display == 'none' ? false : true; } if(isVisible==true) { value = document.getElementById(elementId).value; if(value != '' || setIfBlank == true) { uci.set(pkg, section, option, modFunction(value)); } } } function setVariableFromCombined(params) { elementIds = params[0] visibilityId = params[1]; uci = params[2]; pkg = params[3]; section = params[4]; option = params[5]; setIfBlank = params[6]; combineFunction = params[7]; isVisible = true; if(visibilityId != null) { isVisible = document.getElementById(visibilityId).style.display == 'none' ? false : true; } if(isVisible==true) { values = new Array(); for (idIndex in elementIds) { values.push(document.getElementById(elementIds[idIndex]).value); } if(value != '' || setIfBlank == true) { uci.set(pkg, section, option, combineFunction(values)); } } } function setVariableFromConcatenation(params) { elementIds = params[0]; visibilityIds= params[1]; uci = params[2]; pkg = params[3]; section = params[4]; option = params[5]; setIfBlank = params[6]; concat = ''; nextIdIndex = 0; while(nextIdIndex < elementIds.length) { idVisible = true; if(visibilityIds != null) { nextVisId = visibilityIds[nextIdIndex]; if(nextVisId!= null) { idVisible = document.getElementById(nextVisId).style.display == 'none' ? false : true; } } value = document.getElementById(elementIds[nextIdIndex]).value; if(idVisible==true && value != '') { value = document.getElementById(elementIds[nextIdIndex]).value; endSpace = nextIdIndex < elementIds.length - 1 ? " " : ""; concat = concat + value + endSpace; } nextIdIndex++; } if(concat != '' || setIfBlank == true) { uci.set(pkg, section, option, concat); } } function setVariableConditionally(params) { elementId = params[0]; visibilityId = params[1]; uci = params[2]; pkg = params[3]; section = params[4]; option = params[5]; testFunction = params[6]; useValueFromElement = params[7]; alternateValue = params[8]; isVisible = true; if(visibilityId != null) { isVisible = document.getElementById(visibilityId).style.display == 'none' ? false : true; } if(isVisible==true) { value = useValueFromElement == true ? document.getElementById(elementId).value : alternateValue; if(testFunction(value)) { uci.set(pkg, section, option, value); } } } function setVariables(inputIds, visibilityIds, uci, pkgs, sections, options, setFunctions, additionalParameters) { for (idIndex in inputIds) { nextId = inputIds[idIndex]; nextVisibilityId = visibilityIds[idIndex]; nextPkg = pkgs[idIndex]; nextSection = sections[idIndex]; nextOption = options[idIndex]; nextParams = additionalParameters[idIndex]; nextFunction = setFunctions[idIndex]; if(isArray(nextParams)) { fullList = [nextId, nextVisibilityId, uci, nextPkg, nextSection, nextOption]; for (pIndex in nextParams) { fullList.push(nextParams[pIndex]); } nextFunction(fullList); } else { nextFunction([nextId, nextVisibilityId, uci, nextPkg, nextSection, nextOption, nextParams]); } } } function loadSelectedValueFromVariable(params) { var elementId = params[0]; var uci = params[1]; var pkg = params[2]; var section = params[3]; var option = params[4]; var defaultValue = params[5]; var v=uci.get(pkg, section, option); if(v != null && v != '') { setSelectedValue(elementId, v); } else if(defaultValue != null) { setSelectedValue(elementId, defaultValue); } } function loadValueFromVariable(params) { var elementId = params[0]; var uci = params[1]; var pkg = params[2]; var section = params[3]; var option = params[4]; var defaultValue = params[5]; var v=uci.get(pkg, section, option); var e=document.getElementById(elementId); if(v != null && v != '') { e.value = v; } else if(defaultValue != null) { e.value = defaultValue; } } function loadValueFromVariableMultiple(params) { var multiple = params[6]; loadValueFromVariable(params); var e=document.getElementById(params[0]); e.value=e.value*multiple; } function loadValueFromModifiedVariable(params) { var elementId = params[0]; var uci = params[1]; var pkg = params[2]; var section = params[3]; var option = params[4]; var defaultValue = params[5]; var modificationFunction = params[6]; var v=modificationFunction(uci.get(pkg, section, option)); var e=document.getElementById(elementId); if(v != null && v != '') { e.value = v; } else if(defaultValue != null) { e.value = defaultValue; } } function loadValueFromVariableAtIndex(params) { var elementId = params[0]; var uci = params[1]; var pkg = params[2]; var section = params[3]; var option = params[4]; var defaultValue = params[5]; var index = params[6]; var vStr=uci.get(pkg, section, option); var vSplit = vStr.split(/[,\t ]+/); var v; if(index < vSplit.length) { v=vSplit[index]; } else { v = ''; } var e=document.getElementById(elementId); if(v != null && v != '') { e.value = v; } else if(defaultValue != null) { e.value = defaultValue; } } function loadChecked(params) { var elementId = params[0]; var uci = params[1]; var pkg = params[2]; var section = params[3]; var option = params[4]; var test = params[5]; document.getElementById(params[0]).checked = test(uci.get(pkg,section,option)); } function isArray(obj) { return (obj.constructor.toString().indexOf('Array') >= 0 || obj instanceof Array ? true : false); } function loadVariables(uci, varIds, varPkgs, varSections, varOptions, varParams, varFunctions) { for (idIndex in varIds) { nextId = varIds[idIndex]; nextPkg = varPkgs[idIndex]; nextSection = varSections[idIndex]; nextOption = varOptions[idIndex]; nextParams = varParams[idIndex]; nextFunc = varFunctions[idIndex]; if(isArray(nextParams)) { fullList = [nextId, uci, nextPkg, nextSection, nextOption] for (pIndex in nextParams) { fullList.push(nextParams[pIndex]); } nextFunc(fullList); } else { nextFunc([nextId, uci, nextPkg, nextSection, nextOption, nextParams]); } } } function loadValueFromMultipleVariables(params) { var elementId = params[0]; var uci = params[1]; var pkgs = params[2]; var sections = params[3]; var options = params[4]; var combineFunc = params[5]; var defaultValue = params[6]; var values = new Array(); for (pkgIndex in pkgs) { values.push(uci.get(pkgs[pkgIndex], sections[pkgIndex], options[pkgIndex])); } var combined = combineFunc(values); var e=document.getElementById(elementId); if(combined != null && combined != '') { e.value = combined; } else if(defaultValue != null) { e.value = defaultValue; } } function setVisibility(ids, visibility, defaultDisplays, controlDocument) { if(controlDocument == null) { controlDocument = document; } for (index in ids) { element = controlDocument.getElementById(ids[index]); if(visibility[index] == 0) { element.style.display = "none"; } else { if(defaultDisplays) { element.style.display = defaultDisplays[index]; } else { element.style.display = "block"; } } } } function validateIP(address) { //return codes: //0 == valid IP //1 = 0.0.0.0 //2 = 255.255.255.255 //3 = ends with 255 (actually, broadcast address can end with other value if subnet smaller than 255... but let's not worry about that) //4 = value >255 in at least one field //5 = improper format var errorCode = 0; if(address == "0.0.0.0") { errorCode = 1; } else if(address == "255.255.255.255") { errorCode = 2; } else { var ipFields = address.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/); if(ipFields == null) { errorCode = 5; } else { for(field=1; field <= 4; field++) { if(ipFields[field] > 255) { errorCode = 4; } if(ipFields[field] == 255 && field==4) { errorCode = 3; } } } } return errorCode; } function validateMac(mac) { var errorCode = 0; var macFields = mac.split(/:/); if(macFields.length != 6) { errorCode = 2; } else { for(fieldIndex=0; fieldIndex < 6 && errorCode == 0; fieldIndex++) { field = macFields[fieldIndex]; if(field.match(/^[0123456789ABCDEFabcdef]{2}$/) == null) { errorCode = 1; } } } return errorCode; } function validateMultipleIps(ips) { ips = ips.replace(/^[\t ]+/g, ""); ips = ips.replace(/[\t ]+$/g, ""); var splitIps = ips.split(/[\t ]*,[\t ]*/); var valid = splitIps.length > 0 ? 0 : 1; //1= error, 0=true while(valid == 0 && splitIps.length > 0) { var nextIp = splitIps.pop(); if(nextIp.match(/-/)) { var nextSplit = nextIp.split(/[\t ]*-[\t ]*/); if( nextSplit.length==2 && validateIP(nextSplit[0]) == 0 && validateIP(nextSplit[1]) == 0) { var ipInt1 = getIpInteger(nextSplit[0]); var ipInt2 = getIpInteger(nextSplit[1]); valid = ipInt1 <= ipInt2 ? 0 : 1; } else { valid = 1; } } else { valid = validateIpRange(nextIp); } } return valid; } function validateMultipleIpsOrMacs(addresses) { var addr = addresses.replace(/^[\t ]+/g, ""); addr = addr.replace(/[\t ]+$/g, ""); var splitAddr = addr.split(/[\t ]*,[\t ]*/); var valid = splitAddr.length > 0 ? 0 : 1; //1= error, 0=true while(valid == 0 && splitAddr.length > 0) { var nextAddr = splitAddr.pop(); if(nextAddr.match(/-/)) { var nextSplit = nextAddr.split(/[\t ]*-[\t ]*/); if( nextSplit.length==2 && validateIP(nextSplit[0]) == 0 && validateIP(nextSplit[1]) == 0) { var ipInt1 = getIpInteger(nextSplit[0]); var ipInt2 = getIpInteger(nextSplit[1]); valid = ipInt1 <= ipInt2 ? 0 : 1; } else { valid = 1; } } else if(nextAddr.match(/:/)) { valid = validateMac(nextAddr); } else { valid = validateIpRange(nextAddr); } } return valid; } function validateDecimal(num) { var errorCode = num.match(/^[\d]*\.?[\d]+$/) != null || num.match(/^[\d]+\.?[\d]*$/) != null ? 0 : 1; return errorCode; } function validateNumeric(num) { var errorCode = num.match(/^[\d]+$/) == null ? 1 : 0; return errorCode; } function validatePort(port) { return validateNumericRange(port, 1, 65535) } function validateNumericRange(num, min, max) { var errorCode = num.match(/^[\d]+$/) == null ? 1 : 0; if(errorCode == 0) { errorCode = num < min ? 2 : 0; } if(errorCode == 0) { errorCode = num > max ? 3 : 0; } return errorCode; } function validatePortOrPortRange(ports) { var errorCode = 0; if(ports.match(/-/) != null) { var splitPorts=ports.split(/-/); if(splitPorts.length > 2) { errorCode = 5; } else { error1 = validateNumericRange(splitPorts[0], 1, 65535); error2 = validateNumericRange(splitPorts[1], 1, 65535); errorCode = error1 + (10*error2); if(errorCode == 0) { errorCode = splitPorts[1] - splitPorts[0] >= 0 ? 0 : 4; } } } else { errorCode = validateNumericRange(ports, 1, 65535); } return errorCode; } function validateNetMask(mask) { //return codes: //0 = valid mask //1 = invalid digit //2 = invalid field order //3 = fields > 255 //4 = invalid format var errorCode = 0; var ipFields = mask.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/); if(ipFields == null) { errorCode = 4; } else { previousField = 255; for(field=1; field <= 4; field++) { if(ipFields[field] > 255) { errorCode = 3; } if(previousField < 255 && ipFields[field] != 0 && errorCode < 2) { errorCode = 2; } if( ipFields[field] != 255 && ipFields[field] != 254 && ipFields[field] != 252 && ipFields[field] != 248 && ipFields[field] != 240 && ipFields[field] != 224 && ipFields[field] != 192 && ipFields[field] != 128 && ipFields[field] != 0 && errorCode < 1 ) { errorCode = 1; } previousField = ipFields[field]; } } return errorCode; } //this is for source/destination in iptables //netmask can optionally be specified with / after ip to indicate range function validateIpRange(range) { var valid = 1; //initially invalid, 0=valid, 1=invalid if(range.indexOf("/") > 0) { var split=range.split("/"); if(split.length == 2) { var ipValid = validateIP(split[0]); var maskValid = validateNetMask(split[1]) == 0 || validateNumericRange(split[1],1,31) == 0 ? 0 : 1; valid = ipValid == 0 && maskValid == 0 ? 0 : 1; } } else { valid = validateIP(range); } return valid; } function validateLengthRange(text,min,max) { var errorcode = 0; if(text.length < min) { errorcode = 1; } if(text.length > max) { errorcode = 2; } return errorcode; } function validateHex(text) { var errorcode = 0; if(!text.match(/^[0123456789AaBbCcDdEeFf]*$/)) { errorcode = 1; } return errorcode; } function validateSsid(ssid) { return validateLengthRange(ssid, 1, 32) } function proofreadSsid(input) { proofreadText(input, validateSsid, 0); } function validateHours(hoursStr) { var commaSplit = hoursStr.match(/,/) ? hoursStr.split(/,/) : [ hoursStr ] ; var valid = true; for(commaIndex = 0; commaIndex < commaSplit.length && valid; commaIndex++) { var splitStr = commaSplit[commaIndex].split(/-/); var nextValid = splitStr.length == 2; if(nextValid) { nextValid = nextValid && splitStr[0].match(/^[\t ]*([0-1]?[0-9]|2[0-3])(:[0-5][0-9])?[\t ]*$/) nextValid = nextValid && splitStr[1].match(/^[\t ]*([0-1]?[0-9]|2[0-3])(:[0-5][0-9])?[\t ]*$/) } valid = valid && nextValid; } return valid ? 0 : 1; } function validateWeeklyRange(weeklyStr) { var commaSplit = weeklyStr.match(/,/) ? weeklyStr.split(/,/) : [ weeklyStr ] ; var valid = true; for(commaIndex = 0; commaIndex < commaSplit.length && valid; commaIndex++) { var splitStr = commaSplit[commaIndex].split(/-/); var nextValid = splitStr.length == 2; if(nextValid) { var dayReg=new RegExp("^[\\t ]*("+UI.Sun+"|"+UI.Mon+"|"+UI.Tue+"|"+UI.Wed+"|"+UI.Thu+"|"+UI.Fri+"|"+UI.Sat+")[\\t ]*([0-1]?[0-9]|2[0-3])(:[0-5]?[0-9])?(:[0-5]?[0-9])?[\\t ]*$"); nextValid = nextValid && splitStr[0].match(dayReg); nextValid = nextValid && splitStr[1].match(dayReg); } valid = valid && nextValid; } return valid ? 0 : 1; } function proofreadHours(input) { proofreadText(input, validateHours, 0); } function proofreadWeeklyRange(input) { proofreadText(input, validateWeeklyRange, 0); } function proofreadLengthRange(input,min,max) { var vlr = function(text){return validateLengthRange(text,min,max);}; proofreadText(input, vlr, 0); } function proofreadIp(input) { proofreadText(input, validateIP, 0); } function proofreadMask(input) { proofreadText(input, validateNetMask, 0); } function proofreadIpRange(input) { proofreadText(input, validateIpRange, 0); } function proofreadMac(input) { proofreadText(input, validateMac, 0); } function proofreadMultipleIps(input) { proofreadText(input, validateMultipleIps, 0); } function proofreadMultipleIpsOrMacs(input) { proofreadText(input, validateMultipleIpsOrMacs, 0); } function proofreadDecimal(input) { proofreadText(input, validateDecimal, 0); } function proofreadNumeric(input) { proofreadText(input, validateNumeric, 0); } function proofreadNumericRange(input, min, max) { proofreadText(input, function(text){return validateNumericRange(text,min,max)}, 0); } function proofreadPort(input) { proofreadText(input, validatePort, 0); } function proofreadPortOrPortRange(input) { proofreadText(input, validatePortOrPortRange, 0); } function proofreadText(input, proofFunction, validReturnCode) { if(input.disabled != true) { input.style.color = (proofFunction(input.value) == validReturnCode) ? "" : "red"; } } function resetProofreadText(input) { input.style.color = ""; } function getEmbeddedSvgWindow(embeddedId, controlDocument) { if(controlDocument == null) { controlDocument = document; } var embedElement = controlDocument.getElementById( embeddedId ); var windowElement = null; try { var docElement = embedElement.getSVGDocument(); windowElement = docElement.defaultView; } catch(ex1){} if(windowElement == null) { try { windowElement = embedElement.window; } catch(ex2){} if( windowElement == null) { try { windowElement = embedElement.getWindow(); } catch(ex3){} } } return windowElement; } function getBridgeSection(testUci) { //all bridges will have either option wds=1, option mode=wds, or option client_bridge=1 in one of the wireless sections //in the case of broadcom, the client_bridge=1 doesn't do anything, but we put it there for convenience anyway. //however, if wds is in an AP section, it isn't a bridge var allWirelessSections = uciOriginal.getAllSections("wireless"); var wanDef = uciOriginal.get("network", "wan", ""); var bridgeSection = ""; var sectionIndex; for(sectionIndex=0; sectionIndex < allWirelessSections.length && bridgeSection == ""; sectionIndex++) { var getWirelessVar = function(varName) { return testUci.get("wireless", allWirelessSections[sectionIndex], varName).toLowerCase() } if( getWirelessVar("mode") == "wds" && wanDef == "") { bridgeSection = allWirelessSections[sectionIndex]; } else if( getWirelessVar("mode") == "sta" && getWirelessVar("wds") == "1" && wanDef == "") { bridgeSection = allWirelessSections[sectionIndex]; } else if(getWirelessVar("mode") == "sta" && getWirelessVar("client_bridge") == "1" ) { bridgeSection = allWirelessSections[sectionIndex]; } } return bridgeSection; } function isBridge(testUci) { //is it a router or a bridge configuration? var bridgeTest = getBridgeSection(testUci) == "" ? false : true; return bridgeTest; } //cnv_LocaleTime takes a "21:09" 24hr timestamp // returns a locale-based timestamp (using 12h/24h time prefs & pre/post AM/PM notations): 21:09, 午前 9:09 or 9:09 PM //NOTE: requires uciOriginal to have the 'gargoyle' section; use 'gargoyle_header_footer [options] gargoyle' function cnv24hToLocal(timestamp) { style=uciOriginal.get("gargoyle", "global", "hour_style"); if (style == 24) return timestamp; locale_time="" h_m_stamp=timestamp.split(":"); curr_hour=eval(h_m_stamp[0]); if (UI.pAM.length > 0 && UI.pPM.length > 0) { locale_time+=(curr_hour < 12 ? UI.pAM : UI.pPM)+" " locale_time+=(curr_hour == 0 ? "12" : (curr_hour <= 12 ? curr_hour : curr_hour-12) )+":" + h_m_stamp[1] } else { locale_time+=(curr_hour == 0 ? "12" : (curr_hour <= 12 ? curr_hour : curr_hour-12) )+":" + h_m_stamp[1] locale_time+=" "+(curr_hour < 12 ? UI.hAM : UI.hPM); } return locale_time } //cnv_LocaleTime takes a full "09/16/13 21:09 EDT" date/time stamp // returns (based on hour prefs & pre/post AM/PM notations): "09/16/13 21:09 EDT", "09/16/13 午前 9:09 UTC" or "09/16/13 9:09 PM EDT" //NOTE: requires uciOriginal to have the 'gargoyle' section; use 'gargoyle_header_footer [options] gargoyle' function cnv_LocaleTime(full_date) { // style=uciOriginal.get("gargoyle", "global", "hour_style"); if (style == 24) return full_date; tcomponents=full_date.split(" "); return tcomponents[0]+" "+cnv24hToLocal(tcomponents[1])+" "+tcomponents[2] } function parseTimezones(timezoneLines) { timezoneList = []; timezoneRegions = []; timezoneDefinitions = []; definitionTimezones = []; for(lineIndex = 0; lineIndex < timezoneLines.length; lineIndex++) { line = timezoneLines[lineIndex]; if(!line.match(/^[\t ]*#/) && line.length > 0) { splitLine = line.split(/[\t]+/); region = stripQuotes( splitLine.pop() ); definition = stripQuotes( splitLine.pop() ); timezone = stripQuotes( splitLine.pop() ); if (ObjLen(TiZ) > 0) { //localized firmware will = 0 tz_parts=timezone.split(" "); if (tz_parts.length == 2 && tz_parts[1].search("TiZ.") == 0) { timezone=tz_parts[0]+" "+eval(tz_parts[1]); } } timezoneList.push(timezone); timezoneDefinitions[timezone] = definition; definitionTimezones[definition] = timezone; timezoneRegions[timezone] = region; } } return [timezoneList, timezoneRegions, timezoneDefinitions, definitionTimezones]; } function stripQuotes(str) { if(str.match(/\".*\"/)) { str = str.match(/^[^\"]*\"([^\"]*)\"/)[1]; } return str; } function textListToSpanElement(textList, addCommas, controlDocument) { addCommas = addCommas == null ? false : addCommas; controlDocument = controlDocument == null ? document : controlDocument; var spanEl = controlDocument.createElement("span"); var tlIndex; for(tlIndex=0; tlIndex < textList.length ; tlIndex++) { if(tlIndex > 0) { spanEl.appendChild( controlDocument.createElement("br") ); } spanEl.appendChild(controlDocument.createTextNode( textList[tlIndex] + (tlIndex < textList.length-1 && addCommas ? "," : "") )); } return spanEl; } function addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) { //ipValidType: 0=none, 1=ip only, 2=ip or ip subnet, 3=ip, ip subnet or ip range, 4=ip only, 5=ip or ipsubnet, 6>=ip, ip subnet or ip range macsValid = macsValid == null ? true : macsValid; ipValidType = ipValidType == null ? 3 : ipValidType; var ipValidFunction; if(ipValidType == 0) { ipValidFunction = function(){ return 1; }; } else if(ipValidType == 1) { ipValidFunction = validateIP; } else if(ipValidType == 2) { ipValidFunction = validateIpRange; } else if(ipValidType == 3) { ipValidFunction = validateMultipleIps; } else if(ipValidType == 4) { ipValidFunction = validateIP6; } else if(ipValidType == 5) { ipValidFunction = validateIp6Range; } else { ipValidFunction = validateMultipleIp6s; } var allCurrentMacs = []; var allCurrentIps = []; var tableContainer = controlDocument.getElementById(tableContainerId); if(tableContainer.firstChild != null) { var table = tableContainer.firstChild; var data = getTableDataArray(table, true, false); var rowIndex; for(rowIndex=0; rowIndex < data.length; rowIndex++) { var addr = data[rowIndex][0]; if(validateMac(addr) == 0) { allCurrentMacs.push(addr); } else { allCurrentIps.push(addr); } } } controlDocument = controlDocument == null ? document : controlDocument; alertOnError = alertOnError == null ? true : alertOnError; var splitAddrs = newAddrs.split(/[\t ]*,[\t ]*/); var valid = splitAddrs.length > 0 ? 0 : 1; //1=error, 0=valid var splitIndex; for(splitIndex=0; splitIndex < splitAddrs.length && valid == 0; splitIndex++) { var addr = splitAddrs[splitIndex]; var macValid = (macsValid && validateMac(addr) == 0); var ipValid = (ipValidFunction(addr) == 0); if(macValid || ipValid) { var currAddrs = macValid ? allCurrentMacs : allCurrentIps; var treatipv6 = false; if(macValid || ipValidType <= 3) { treatipv6 = false; } else { treatipv6 = true; } valid = currAddrs.length == 0 || (!testAddrOverlap(addr, currAddrs.join(","), treatipv6)) ? 0 : 1; if(valid == 0) { currAddrs.push(addr); //if we're adding multiple addrs and there's overlap, this will allow us to detect it } } else { valid = 1; } } if(valid == 0) { var table = tableContainer.childNodes.length > 0 ? tableContainer.firstChild : createTable([""], [], tableId, true, false, null, null, controlDocument); newAddrs = newAddrs.replace(/^[\t ]*/, ""); newAddrs = newAddrs.replace(/[\t ]*$/, ""); var addrs = newAddrs.split(/[\t ]*,[\t ]*/); while(addrs.length > 0) { var tmpaddr = addrs.shift(); if(tmpaddr.indexOf("-") > -1) { var tmpaddrs = tmpaddr.split("-"); if(isIPv6(tmpaddrs[0])) { tmpaddrs[0] = ip6_canonical(tmpaddrs[0]); tmpaddrs[1] = ip6_canonical(tmpaddrs[1]); tmpaddr = tmpaddrs.join("-"); } } else { if(isIPv6(tmpaddr)) { tmpaddr = ip6_canonical(tmpaddr); } } addTableRow(table, [ tmpaddr ], true, false, null, null, controlDocument); } if(tableContainer.childNodes.length == 0) { tableContainer.appendChild(table); } if(tableWidth != null) { table.style.width = "" + tableWidth + "px"; } } else if(alertOnError) { alert(UI.InvAdd+"\n"); } return valid == 0 ? true : false; } function addAddressesToTable(controlDocument, textId, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) { var newAddrs = controlDocument.getElementById(textId).value; var valid = addAddressStringToTable(controlDocument, newAddrs, tableContainerId, tableId, macsValid, ipValidType, alertOnError, tableWidth) if(valid) { controlDocument.getElementById(textId).value = ""; } return valid; } function parsePaddedInt(intStr) { intStr = intStr == null ? "" : intStr; intStr = intStr.replace(/[\t ]+/, ""); while( (intStr.length > 1 && intStr.match(/^0/)) || (intStr.length > 2 && intStr.match(/^\-0/)) ) { intStr = intStr.replace(/^0/, ""); intStr = intStr.replace(/^\-0/, "-"); } return parseInt(intStr); } function getIpInteger(ipStr) { ipStr = ipStr == null ? "" : ipStr; var ip = ipStr.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); if(ip) { return (+parsePaddedInt(ip[1])<<24) + (+parsePaddedInt(ip[2])<<16) + (+parsePaddedInt(ip[3])<<8) + (+parsePaddedInt(ip[4])); } return parseInt(""); //will return NaN } function getMaskInteger(maskSize) { return -1<<(32-parsePaddedInt(maskSize)) } function getIpRangeIntegers(ipStr) { var startInt = 0; var endInt = 0; if(ipStr.match(/\//)) { var split = ipStr.split(/[\t ]*\/[\t ]*/); var ipInt = getIpInteger(split[0]); var ipMaskInt = (split[1]).match(/\./) ? getIpInteger(split[1]) : getMaskInteger(split[1]); startInt = ipInt & ipMaskInt; endInt = startInt | ( ~ipMaskInt ); } else if(ipStr.match(/-/)) { var split = ipStr.split(/[\t ]*\-[\t ]*/); startInt = getIpInteger(split[0]); endInt = getIpInteger(split[1]); } else { startInt = getIpInteger(ipStr); endInt = startInt; } return [startInt, endInt]; } function getIp6RangeStrings(ipStr) { var startStr = ""; var endStr = ""; if(ipStr.match(/\//)) { var split = ipStr.split(/[\t ]*\/[\t ]*/); startStr = ip6_full(ip6_mask(split[0],split[1])); var startBin = ip6addr2bin(startStr); endStr = ip6bin2addr(startBin.substr(0,split[1]) + '1'.repeat(128-split[1])); } else if(ipStr.match(/-/)) { var split = ipStr.split(/[\t ]*\-[\t ]*/); startStr = ip6_full(split[0]); endStr = ip6_full(split[1]); } else { startStr = ip6_full(ipStr); endStr = startStr; } return [startStr, endStr]; } function ip6addr2bin(addr) { var ip6addr = ip6_full(addr); var sections = ip6addr.split(":"); var binaddr = ""; for(var x = 0; x < sections.length; x++) { binaddr += parseInt(sections[x],16).toString(2).padStart(16,'0'); } return binaddr; } function ip6bin2addr(bin) { var sections = []; for(var x = 0; x < 8; x++) { var section = bin.substr(x*16, 16); var hexsection = parseInt(section, 2).toString(16).padStart(4,'0'); sections.push(hexsection); } return sections.join(":"); } function testSingleAddrOverlap(addrStr1, addrStr2, treatipv6) { /* * this adjustment is useful in multiple places, particularly quotas * if you don't want these conversions, just validate quota BEFORE you * try calling this function */ var adj = function(addrStr) { addrStr = addrStr == "" ? "ALL" : addrStr.toUpperCase(); if(addrStr == "ALL_OTHERS_COMBINED" || addrStr == "ALL_OTHERS_INDIVIDUAL") { addrStr = "ALL_OTHERS_COMBINED"; } return addrStr; } addrStr1 = adj(addrStr1); addrStr2 = adj(addrStr2); var matches = false; if(addrStr1 == addrStr2) //can test MAC addr equality as well as ALL/OTHER variables we use sometimes { matches = true; } else //assume we're dealing with an actual IP / IP subnet / IP Range { if(treatipv6) { if(validateMultipleIp6s(addrStr1) > 0 || validateMultipleIp6s(addrStr2) > 0 || addrStr1.match(",") || addrStr2.match(",") ) { matches = false; } else { var parsed1 = getIp6RangeStrings(addrStr1); var parsed2 = getIp6RangeStrings(addrStr2); matches = parsed1[0] <= parsed2[1] && parsed1[1] >= parsed2[0]; //test range overlap, inclusive } } else { if(validateMultipleIps(addrStr1) > 0 || validateMultipleIps(addrStr2) > 0 || addrStr1.match(",") || addrStr2.match(",") ) { matches = false; } else { var parsed1 = getIpRangeIntegers(addrStr1); var parsed2 = getIpRangeIntegers(addrStr2); matches = parsed1[0] <= parsed2[1] && parsed1[1] >= parsed2[0]; //test range overlap, inclusive } } } return matches; } function testAddrOverlap(addrStr1, addrStr2, treatipv6) { treatipv6 = treatipv6 == true ? treatipv6 : false; addrStr1 = addrStr1.replace(/^[\t ]+/, ""); addrStr1 = addrStr1.replace(/[\t ]+$/, ""); addrStr2 = addrStr2.replace(/^[\t ]+/, ""); addrStr2 = addrStr2.replace(/[\t ]+$/, ""); var split1 = addrStr1.split(/[,\t ]+/); var split2 = addrStr2.split(/[,\t ]+/); var index1; var overlapFound = false; for(index1=0; index1 < split1.length && (!overlapFound); index1++) { var index2; for(index2=0; index2 0) { var nextProto = protoList.shift(); if(foundPorts[nextProto][remotePort] == null) //bypasses adding second instance defs if already defined above as part of ssh/http/https { portDefs.push( [ remotePort, nextProto, UI.prdr ]) foundPorts[nextProto][remotePort] = 1; if(foundPorts[nextProto][localPort] == null) //implies localPort != remotePort, since we just set this for remotePort { portDefs.push([localPort, nextProto, UI.puse ]) foundPorts[nextProto][localPort] = 1 } } } } if(localPort == "" && startPort != "" && endPort != "") { var protoList = proto == "" || proto == "tcpudp" ? [ "tcp", "udp" ] : [ proto ]; while(protoList.length > 0) { var nextProto = protoList.shift(); portDefs.push([startPort + "-" + endPort, nextProto, UI.prdr ]) } } } } var redirectSections = uciOriginal.getAllSectionsOfType("firewall", "redirect") var redirectIndex; for(redirectIndex=0; redirectIndex < redirectSections.length; redirectIndex++) { var section = remoteAcceptSections[acceptIndex]; var localPort = uciOriginal.get("firewall", section, "local_port"); var remotePort = uciOriginal.get("firewall", section, "remote_port"); var proto = uciOriginal.get("firewall", section, "proto").toLowerCase(); var srcZone = uciOriginal.get("firewall", section, "src").toLowerCase(); var dstZone = uciOriginal.get("firewall", section, "dest").toLowerCase(); var port = uciOriginal.get("firewall", section, "src_dport") var ip = uciOriginal.get("firewall", section, "dest_ip"); //note range notation already part of remotePort here, so range is handled properly by this code portDefs.push([remotePort, proto, UI.pfwd+" " + ip ]) } //for debugging only /* var portStr = []; var pi; for(pi=0; pi< portDefs.length; pi++) { portStr.push( (portDefs[pi]).join(",") ); } alert(portStr.join("\n")); */ return portDefs; } // ignorePorts should be 2d-associateive array with first dimension being proto, second port, eg. ignorePorts[proto][port or port range] = 1 if port is to be ignored function checkForPortConflict(port, proto, ignorePorts) { var portStart = null var portEnd = null var isRange = false if(port.match(/-/)) { var splitPort = port.split(/-/) portStart = parseInt(splitPort[0]) portEnd = parseInt(splitPort[1]) isRange = true; } else { port = parseInt(port) } if(ignorePorts != null) { ignorePorts["tcp"] = ignorePorts["tcp"] == null ? [] : ignorePorts["tcp"] ignorePorts["udp"] = ignorePorts["udp"] == null ? [] : ignorePorts["udp"] if(ignorePorts[proto][port] != null && ignorePorts[proto][(""+port)] != null) { return "" } else { var range for(range in ignorePorts[proto]) { if(range.match(/-/)) { var splitRange = range.split(/-/); if((!isRange) && port >= parseInt(splitRange[0]) && port <= parseInt(splitRange[1])) { return "" } if(isRange && portStart <= parseInt(splitRange[1]) && portEnd >= parseInt(splitRange[0])) { return "" } } } } } var usedPorts = getUsedPorts() var portIndex; var portConflict = "" for(portIndex=0; portIndex < usedPorts.length && portConflict == ""; portIndex++) { var portDef = usedPorts[portIndex]; if(proto == portDef[1]) { var portStr = portDef[0] if(portStr.match(/\-/)) { var splitPort = portStr.split(/\-/) if((!isRange) && port >= parseInt(splitPort[0]) && port <= parseInt(splitPort[1])) { portConflict = portDef[2] } if(isRange && portStart <= parseInt(splitPort[1]) && portEnd >= parseInt(splitPort[0])) { portConflict = portDef[2] } } else { if((!isRange) && port == parseInt(portStr)) { portConflict = portDef[2] } if(isRange && parseInt(portStr) >= portStart && parseInt(portStr) <= portEnd) { portConflict = portDef[2] } } } } return portConflict; } function query(queryHeader, queryText, buttonNameList, continueFunction ) { document.getElementById("wait_icon").style.display="none" document.getElementById("wait_txt").style.display="none" wmOldTxt = document.getElementById("wait_txt").style == "none" ? false : true; wmOldBack = document.getElementById("wait_msg").style.background wmOldWidth = document.getElementById("wait_msg").style.width; wmOldHeight = document.getElementById("wait_msg").style.height wmOldTop = document.getElementById("wait_msg").style.top document.getElementById("wait_msg").style.background="white" document.getElementById("wait_msg").style.width="585px" document.getElementById("wait_msg").style.height="auto" setControlsEnabled(false,false) document.getElementById("wait_msg").style.top="20px" queryFieldset = document.createElement("fieldset"); queryFieldset.innerHTML='' + queryHeader + '
' + queryText + '
 
' document.getElementById("wait_msg").appendChild(queryFieldset) var buttonList = []; var bIndex; for(bIndex=0; bIndex < buttonNameList.length ; bIndex++) { b = createInput("button", document); b.textContent = buttonNameList[bIndex]; b.value = buttonNameList[bIndex]; b.className = "btn btn-default" b.style = "margin-bottom: 5px;"; b.onclick = function() { document.getElementById("wait_msg").removeChild(queryFieldset) document.getElementById("wait_msg").style.background=wmOldBack document.getElementById("wait_msg").style.width=wmOldWidth document.getElementById("wait_msg").style.height=wmOldHeight document.getElementById("wait_msg").style.top=wmOldTop document.getElementById("wait_icon").style.display="block" document.getElementById("wait_txt").style.display="block" setControlsEnabled(false,wmOldTxt) continueFunction(this.value) } document.getElementById("query_button_container").appendChild(b); document.getElementById("query_button_container").appendChild( document.createElement("br") ) } } function getKeyByValue(object, value) { return Object.keys(object).find(key => object[key] === value); } //apparently these var fbS=new Object(); //part of i18n -> objects do not have a length (it is undefined) function ObjLen(an_obj) { var len=0; for (item in an_obj) { len++; } return len } function reregisterTableSort() { TSort_Classes = new Array ('odd', 'even'); // table sorting zebra row support var args = Array.prototype.slice.call(arguments); TSort_Data = args; TSort_Initial = '0A'; tsRegister(); tsSetTable (args[0]); tsInit(); } //Part of the new popups in GUI. Pass the parent element containing the "popup span" function togglePopup(popElement) { var descendant = popElement.getElementsByTagName("span"); if (descendant.length != 1) { return null; } descendant[0].classList.toggle("show"); } //Part of collapsible menus scripts function uncollapseNavThis(menuElement) { var parentNav = menuElement.parentElement; collapseNavOthers(parentNav); parentNav.classList.add("active"); var siblings = parentNav.childNodes; for (var x = 0; x < siblings.length; x++) { if (siblings[x].nodeName == "UL") { siblings[x].classList.add("active"); } } } function collapseNavOthers(navElement) { var excludedNavID = navElement.id; var x = 0; var elem; for(x = 0; x < menuState.length; x++) { elem = document.getElementById(menuState[x][0]); if((elem != null) && (elem.id != excludedNavID) && (elem.id.endsWith("_MIN00"))) { elem.classList.remove("active"); var descendant = elem.childNodes; for(var y = 0; y < descendant.length; y++) { if(descendant[y].nodeName == "UL") { descendant[y].classList.remove("active"); } } } } } function storeNavState() { var selectorStart = "nav_MAJ"; var selectorEnd = "_MIN"; var x = 1; var y = 0; var selectorStr; var elem; var elemSub; function createSelectorString(selectorStart,x,selectorEnd,y) { selectorString = selectorStart + ("0" + x).slice(-2) + selectorEnd + ("0" + y).slice(-2); return selectorString; } selectorStr = createSelectorString(selectorStart,x,selectorEnd,y); elem = document.getElementById(selectorStr); while(elem != null) { menuState.push([elem.id,elem.className]) y++; selectorStr = createSelectorString(selectorStart,x,selectorEnd,y); elemSub = document.getElementById(selectorStr); while(elemSub != null) { menuState.push([elemSub.id,elemSub.className]) y++; selectorStr = createSelectorString(selectorStart,x,selectorEnd,y); elemSub = document.getElementById(selectorStr); } y = 0; x++; selectorStr = createSelectorString(selectorStart,x,selectorEnd,y); elem = document.getElementById(selectorStr); } } function restoreNavState() { var x = 0; var elem; for(x = 0; x < menuState.length; x++) { elem = document.getElementById(menuState[x][0]); if(elem != null) { elem.className = menuState[x][1]; } } } function setNavMouseEvents() { var navSidebar = document.getElementById("sidebar") if(navSidebar == null) { return; } navSidebar.onmouseover = function() { clearTimeout(navTimer) ; } navSidebar.onmouseleave = function() { navTimer = setTimeout(restoreNavState,1200) } var sidebarElements = document.getElementsByClassName("sidebar-item") var i; for(i=0; i< sidebarElements.length; i++) { e = sidebarElements[i]; if(e.id.match(/MIN00/) && e.firstChild != null ) { subId = e.id.replace(/MIN00/, "MIN01") subEl = document.getElementById(subId) if(subEl == null) { //do nothing to logout link } else { e.firstChild.onmouseover = function() {} e.firstChild.onclick = function() { var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; if( windowWidth <= 991 ) { uncollapseNavThis(this); } else { var topId = this.parentNode.id; var topIdPrefix = topId.substr(0, topId.length - 2) var listEl = document.getElementById(topIdPrefix + "01") if(listEl != null && listEl.firstChild != null && listEl.firstChild.href != null) { window.location = listEl.firstChild.href } } return false } } } } storeNavState(); } function sidebar() { var row = document.getElementById("row-offcanvas"); if(row.className == "row-offcanvas full-height active") { row.className = "row-offcanvas full-height"; } else { row.className = "row-offcanvas full-height active"; } } function setupModalKeys(name) { //Find all selectable elements so we can store the first and last ones //Note that in this implementation we will always include the modal itself in the tab order as the zeroth element modal = document.getElementById(name); focusableEls = modal.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"]'); focusableEls = Array.prototype.slice.call(focusableEls); firstFocusableEl = focusableEls[0]; lastFocusableEl = focusableEls[focusableEls.length-1]; handleEscapeKey = function() { closeModalWindow(name); }; handleBackwardsTab = function(e) { if(document.activeElement === modal) { e.preventDefault(); lastFocusableEl.focus(); } else if(document.activeElement === firstFocusableEl) { e.preventDefault(); modal.focus(); } }; handleForwardsTab = function(e) { if(document.activeElement === lastFocusableEl) { e.preventDefault(); modal.focus(); } }; handleModalKeys = function(e) { KEY_ESC = "Escape"; KEY_TAB = "Tab"; switch(e.key) { case KEY_ESC: handleEscapeKey(); break; case KEY_TAB: if(focusableEls.length == 1) { e.preventDefault(); break; } else if(e.shiftKey) { handleBackwardsTab(e); } else { handleForwardsTab(e); } break; default: break; } }; document.onkeydown = handleModalKeys; } function openPopupWindow(url, name, width, height) { var xCoor = (window.outerWidth - width)/2; var yCoor = (window.outerHeight - height)/2; return window.open(url, name, "width=" + width + ",height=" + height + ",left=" + xCoor + ",top=" + yCoor); } function openModalWindow(name) { var modal = document.getElementById(name); modal.classList.add("in"); //Remove aria-hidden attribute modal.removeAttribute('aria-hidden'); //Capture modal keys setupModalKeys(name); //Store the element to restore focus modalTriggerElement = document.activeElement; //Focus the modal modal.focus(); } function closeModalWindow(name) { var modal = document.getElementById(name); modal.classList.remove("in"); //Restore aria-hidden attribute modal.setAttribute("aria-hidden","true"); //Uncapture ESC key document.onkeydown = null; //Restore focus if(modalTriggerElement !== null) { modalTriggerElement.focus() } } function modalPrepare(modalID, title, elements, buttons) { defaultDismiss = document.createElement("button"); defaultDismiss.onclick = function(){closeModalWindow(modalID);}; defaultDismiss.className = "btn btn-warning"; defaultDismiss.innerText = UI.Cancel; defaultDismiss.id = "modal_button_default_dismiss"; defaultDiscard = document.createElement("button"); defaultDiscard.onclick = function(){closeModalWindow(modalID);}; defaultDiscard.className = "btn btn-warning"; defaultDiscard.innerText = UI.CDiscardChanges; defaultDiscard.id = "modal_button_default_discard"; titleEl = document.getElementById(modalID + "_title"); if(titleEl) { titleEl.innerHTML = title; } btnContainer = document.getElementById(modalID + "_button_container"); while(btnContainer.children.length > 0) { btnContainer.removeChild(btnContainer.children[0]); } elements.forEach(function(element) { inputEl = document.getElementById(element.id); if(inputEl) { if(element.options !== undefined) { removeAllOptionsFromSelectElement(inputEl); for (var key in element.options) { var optEl = document.createElement('option'); optEl.innerHTML = element.options[key]; optEl.value = key; inputEl.options.add(optEl); } } if(element.value !== undefined) { inputEl.value = element.value; } if(element.values !== undefined) { for(var x = 0; x < inputEl.options.length; x++) { inputEl.options[x].selected = false; if(element.values.indexOf(inputEl.options[x].value) > -1) { inputEl.options[x].selected = true; } } } if(element.innertext !== undefined) { inputEl.innerText = element.innertext; } if(element.checked !== undefined) { inputEl.checked = element.checked; } if(element.disable !== undefined) { inputEl.disabled = element.disable; } } }); buttons.forEach(function(button) { if(button == "defaultDismiss") { btnContainer.appendChild(defaultDismiss); } else if(button == "defaultDiscard") { btnContainer.appendChild(defaultDiscard); } else { btnEl = document.createElement("button"); btnEl.className = button.classes; btnEl.onclick = button.function; btnEl.innerText = button.title; if(button.id !== undefined) { btnEl.id = button.id; } if(button.disabled !== undefined) { btnEl.disabled = button.disabled; } btnContainer.appendChild(btnEl); } }); } //IPv6 library function ip6_full(address) { var tmpAddr = ip6_splitmask(address); //replace ipv4 address var ipv4 = tmpAddr.address.match(/(.*:)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$)/); if (ipv4) { tmpAddr.address = ipv4[1]; ipv4 = ipv4[2].match(/[0-9]+/g); for (var i = 0;i < 4;i ++) { var byte = parseInt(ipv4[i],10); ipv4[i] = ("0" + byte.toString(16)).substr(-2); } tmpAddr.address += ipv4[0] + ipv4[1] + ':' + ipv4[2] + ipv4[3]; } //leading and trailing :: tmpAddr.address = tmpAddr.address.replace(/^:|:$/g, ''); var ipv6 = tmpAddr.address.split(':'); for (var i = 0; i < ipv6.length; i ++) { var hex = ipv6[i]; if (hex != "") { //normalize leading zeros ipv6[i] = ("0000" + hex).substr(-4); } else { //normalize grouped zeros :: hex = []; for (var j = ipv6.length; j <= 8; j ++) { hex.push('0000'); } ipv6[i] = hex.join(':'); } } tmpAddr.address = ipv6.join(':'); return (tmpAddr.bitmask == "" ? tmpAddr.address : tmpAddr.address + "/" + tmpAddr.bitmask); } function ip6_canonical(address) { var fullAddress = ip6_full(address); var tmpAddr = ip6_splitmask(fullAddress); var components = tmpAddr.address.split(":"); for(var componentIdx = 0; componentIdx < components.length; componentIdx++) { //suppress leading zeros components[componentIdx] = components[componentIdx].replace(/^0+([1-9a-f]{1,3})/i,'$1'); //convert remaining all zero fields to a single zero components[componentIdx] = components[componentIdx].replace(/^0+/,'0'); } //Shorten longest run of all zeros (that is greater than 1 field) var zeroCounts = []; zeroCounts.length = components.length; zeroCounts.fill(0); inZeroChain = false; firstZeroInChain = 0; for(var componentIdx = 0; componentIdx < components.length; componentIdx++) { if(components[componentIdx] == "0") { if(inZeroChain) { for(var zeroIdx = componentIdx; zeroIdx >= firstZeroInChain; zeroIdx--) { zeroCounts[zeroIdx] = zeroCounts[zeroIdx] + 1; } } else { inZeroChain = true; firstZeroInChain = componentIdx; zeroCounts[componentIdx] = zeroCounts[componentIdx] + 1; } } else { inZeroChain = false; } } maxZeroCount = Math.max.apply(null, zeroCounts); maxZeroCountIdxs = []; for(var idx = 0; (maxZeroCount > 1) && (idx < zeroCounts.length); idx++) { if(zeroCounts[idx] == maxZeroCount) { maxZeroCountIdxs.push(idx); } } if(maxZeroCountIdxs.length > 0) { components.splice(maxZeroCountIdxs[0],maxZeroCount-1) components[maxZeroCountIdxs[0]] = ""; } if(components[0] == "" && components.length == 1) { components.splice(0,0,""); components.splice(0,0,""); } else if(components[0] == "") { components.splice(0,0,""); } else if(components[components.length-1] == "") { components.push(""); } return (tmpAddr.bitmask == "" ? components.join(':') : components.join(':') + "/" + tmpAddr.bitmask); } function ip6_splitmask(address) { var ipv6 = {}; var tmp = address.split("/"); if(tmp.length == 2) { ipv6.address = tmp[0]; ipv6.bitmask = tmp[1]; } else { ipv6.address = tmp[0]; ipv6.bitmask = ""; } return ipv6; } function validateIP6(address) { //return codes: //0 == valid IP //1 = improper format var errorCode = 0; var components = address.split(":"); if((address.match(/:{3,}/)) || (address.match(/::.+::/)) || (address.match(/[^:]:$/)) || (address.match(/^:(?!:)/))) { errorCode = 1; } if(components.length < 2 || components.length > 8) { errorCode = 1; } if(components.length < 8 && !address.match(/::/)) { errorCode = 1; } for(var componentIdx = 0; componentIdx < components.length; componentIdx++) { if(!components[componentIdx].match(/^[0-9a-f]{0,4}$/i)) { errorCode = 1; } } return errorCode; } function proofreadIp6(input) { proofreadText(input, validateIP6, 0); } function validateIP6Range(range) { //return codes: //0 == valid IP //1 = improper format var errorCode = 1; if(range.indexOf("/") > 0) { var split=range.split("/"); if(split.length == 2) { var ipValid = validateIP6(split[0]); var maskValid = split[1] < -128 || split[1] > 128 ? 1 : 0; errorCode = ipValid == 0 && maskValid == 0 ? 0 : 1; } } else { errorCode = validateIP6(range); } return errorCode; } function proofreadIp6Range(input) { proofreadText(input, validateIP6Range, 0); } function validateIP6ForceRange(range) { //return codes: //0 == valid IP //1 = improper format var errorCode = 1; if(range.indexOf("/") > 0) { var split=range.split("/"); if(split.length == 2) { var ipValid = validateIP6(split[0]); var maskValid = split[1] < 1 || split[1] > 128 ? 1 : 0; errorCode = ipValid == 0 && maskValid == 0 ? 0 : 1; } } return errorCode; } function proofreadIp6ForceRange(input) { proofreadText(input, validateIP6ForceRange, 0); } function ip6_mask(address, mask) { var newAddr = ""; var binaddr = ip6addr2bin(address); if(mask < 0) { newAddr = '0'.repeat(128+mask) + binaddr.substr(128+mask); } else { newAddr = binaddr.substr(0,mask) + '0'.repeat(128-mask); } newAddr = ip6bin2addr(newAddr); newAddr = ip6_canonical(newAddr); return newAddr; } function ip6_scope(address) { var retVal = [null, null]; if(ip6_mask(address,3) == "2000::") { retVal = ["Global", "Global Unicast Address"]; } if(ip6_mask(address,32) == "2001::") { retVal = ["Global", "Teredo Tunnel"]; } if(ip6_mask(address,96) == "64:ff9b::") { retVal = ["Global", "IPv4/IPv6 Translation"]; } if(ip6_mask(address,8) == "ff00::") { retVal = ["Global", "Global Multicast Address"]; } if(ip6_mask(address,7) == "fc00::") { retVal = ["Global", "Unique Local Address"]; } if(ip6_mask(address,10) == "fe80::") { retVal = ["Link", "Link-local Address"]; } return retVal; } function getIPFamily(address) { var retVal = null; if(validateIpRange(address) == 0) { retVal = "IPv4"; } else if(validateIP6Range(address) == 0) { retVal = "IPv6"; } return retVal; } function isIPv4(address) { return getIPFamily(address) == "IPv4"; } function isIPv6(address) { return getIPFamily(address) == "IPv6"; } function validateMultipleIp6s(ips) { ips = ips.replace(/^[\t ]+/g, ""); ips = ips.replace(/[\t ]+$/g, ""); var splitIps = ips.split(/[\t ]*,[\t ]*/); var valid = splitIps.length > 0 ? 0 : 1; //1= error, 0=true while(valid == 0 && splitIps.length > 0) { var nextIp = splitIps.pop(); if(nextIp.match(/-/)) { var nextSplit = nextIp.split(/[\t ]*-[\t ]*/); if( nextSplit.length==2 && validateIP6(nextSplit[0]) == 0 && validateIP6(nextSplit[1]) == 0) { var ipFull1 = ip6_full(nextSplit[0]); var ipFull2 = ip6_full(nextSplit[1]); valid = ipFull1 <= ipFull2 ? 0 : 1; } else { valid = 1; } } else { valid = validateIP6Range(nextIp); } } return valid; } function proofreadMultipleIp6s(input) { proofreadText(input, validateMultipleIp6s, 0); } function validateMultipleIp6sOrMacs(ips) { ips = ips.replace(/^[\t ]+/g, ""); ips = ips.replace(/[\t ]+$/g, ""); var splitIps = ips.split(/[\t ]*,[\t ]*/); var valid = splitIps.length > 0 ? 0 : 1; //1= error, 0=true while(valid == 0 && splitIps.length > 0) { var nextIp = splitIps.pop(); if(nextIp.match(/-/)) { var nextSplit = nextIp.split(/[\t ]*-[\t ]*/); if( nextSplit.length==2 && validateIP6(nextSplit[0]) == 0 && validateIP6(nextSplit[1]) == 0) { var ipFull1 = ip6_full(nextSplit[0]); var ipFull2 = ip6_full(nextSplit[1]); valid = ipFull1 <= ipFull2 ? 0 : 1; } else { valid = 1; } } else { if(getIPFamily(nextIp) == null) { valid = validateMac(nextIp); } else { valid = validateIP6Range(nextIp); } } } return valid; } function proofreadMultipleIp6sOrMacs(input) { proofreadText(input, validateMultipleIp6sOrMacs, 0); }