539 lines
23 KiB
HTML
Executable File
539 lines
23 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title id="webtitle"></title>
|
|
<link href="css/styles.css" rel="stylesheet" media="screen">
|
|
<script src="js/auth.js"></script>
|
|
<script src="js/jquery.js"></script>
|
|
<script src="js/dashboard.js"></script>
|
|
<script>
|
|
var lastTime = new Date().getTime();
|
|
var currentTime = new Date().getTime();
|
|
var timeOut = 20 * 60 * 1000; // 20 minutes
|
|
|
|
$(function(){
|
|
// Listen to multiple types of user activity to prevent timeout
|
|
$(document).on('mousemove keydown click scroll touchstart', function(){
|
|
lastTime = new Date().getTime();
|
|
});
|
|
});
|
|
|
|
function testTime(){
|
|
currentTime = new Date().getTime();
|
|
if(currentTime - lastTime > timeOut){
|
|
window.location.href="login.cgi?logout=1";
|
|
}
|
|
}
|
|
|
|
// Timer check (1 second interval)
|
|
window.setInterval(testTime, 1000);
|
|
// Dashboard refresh (3 second interval)
|
|
setInterval(refreshDashboard, 3000);
|
|
|
|
function get_remote_local_ctrl()
|
|
{
|
|
var queryData = "sys_cfg=&";
|
|
$.get("atsc_status_cfg.cgi?"+queryData,function(data, status) {
|
|
// Handle case where data is a JSON object (e.g., session expired)
|
|
if (typeof data === 'object' && data !== null) {
|
|
if (data.error === 'session_expired' && data.redirect) {
|
|
window.location.href = data.redirect;
|
|
return;
|
|
}
|
|
console.error('Received JSON error response:', data);
|
|
return;
|
|
}
|
|
|
|
var table = data.split("|");
|
|
// g_remot_local_ctrl = Number(table[0].split("#")[5]);
|
|
// document.title = table[0].split("#")[11];
|
|
});
|
|
}
|
|
|
|
function refresh_show(){
|
|
//get_remote_local_ctrl();
|
|
SetFormDefaults();
|
|
refreshDashboard();
|
|
}
|
|
|
|
function SetFormDefaults()
|
|
{
|
|
// 1. DISABLE BUTTON START (Optional safety, though HTML handles initial load)
|
|
$('#get_log_btn').attr("disabled", true).val("Loading...");
|
|
// Placeholder for future initialization logic
|
|
var queryData = "web_title=&";
|
|
$.get("atsc_status_cfg.cgi?"+queryData,function(data, status) {
|
|
// Handle case where data is a JSON object (e.g., session expired)
|
|
if (typeof data === 'object' && data !== null) {
|
|
if (data.error === 'session_expired' && data.redirect) {
|
|
window.location.href = data.redirect;
|
|
return;
|
|
}
|
|
console.error('Received JSON error response:', data);
|
|
return;
|
|
}
|
|
|
|
var table = data.split("|");
|
|
var title = table[0].split("#");
|
|
|
|
// 2. RE-ENABLE BUTTON END
|
|
$('#get_log_btn').attr("disabled", false).val("Get");
|
|
|
|
document.getElementById('webtitle').textContent = title[1];
|
|
document.getElementById('webtitle_header').textContent = title[1];
|
|
}).fail(function() {
|
|
// Optional: Error handling
|
|
$('#get_log_btn').val("Load Failed");
|
|
});
|
|
}
|
|
|
|
function cmd_confirm()
|
|
{
|
|
return confirm("Please be patient, log data is being collected!");
|
|
}
|
|
|
|
function log_download_show()
|
|
{
|
|
document.getElementById("id_download").style.visibility="visible";
|
|
}
|
|
|
|
function Get_Log_File()
|
|
{
|
|
if(cmd_confirm()){
|
|
var queryData = "log_output=&";
|
|
$.get("atsc_status_cfg.cgi?"+queryData,function(data, status) {
|
|
// Handle case where data is a JSON object (e.g., session expired)
|
|
if (typeof data === 'object' && data !== null) {
|
|
if (data.error === 'session_expired' && data.redirect) {
|
|
window.location.href = data.redirect;
|
|
return;
|
|
}
|
|
console.error('Received JSON error response:', data);
|
|
return;
|
|
}
|
|
|
|
var table = data.split("|");
|
|
var form0 = table[0].split("#");
|
|
var ret_log = form0[1];
|
|
|
|
if(ret_log == 999){
|
|
setTimeout(log_download_show, 2000);
|
|
} else {
|
|
alert("Log generation failed or system busy. Code: " + ret_log);
|
|
}
|
|
});
|
|
}
|
|
else{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Opens the modal - gets current username from server
|
|
function openAccountModal() {
|
|
// Fetch current username from server
|
|
$.get("login.cgi?action=get_user", function(data) {
|
|
var trimmedData = (data || "").trim();
|
|
if (trimmedData && trimmedData !== "UNAUTHORIZED") {
|
|
document.getElementById('current_user').value = trimmedData;
|
|
}
|
|
document.getElementById('accountModal').style.display = 'block';
|
|
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
|
}).fail(function() {
|
|
document.getElementById('accountModal').style.display = 'block';
|
|
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
|
});
|
|
}
|
|
|
|
// Closes the modal and clears the sensitive inputs
|
|
function closeAccountModal() {
|
|
document.getElementById('accountModal').style.display = 'none';
|
|
document.getElementById('current_pwd').value = '';
|
|
document.getElementById('new_pwd').value = '';
|
|
document.getElementById('confirm_pwd').value = '';
|
|
}
|
|
|
|
// Validates that a string contains only printable characters (excluding space)
|
|
function isValidPrintableString(str) {
|
|
// Regular expression to check for printable characters (ASCII 33-126), excluding space
|
|
// Space is ASCII 32, and we want to exclude it
|
|
var printableCharRegex = /^[!-~]+$/; // ! is ASCII 33, ~ is ASCII 126
|
|
return printableCharRegex.test(str);
|
|
}
|
|
|
|
// Validates the passwords match before submitting to the CGI script - All required fields must be filled
|
|
function validateAccountForm() {
|
|
var currentUser = document.getElementById('current_user').value;
|
|
var currentPwd = document.getElementById('current_pwd').value;
|
|
var newUsername = document.getElementById('new_user').value;
|
|
var newPwd = document.getElementById('new_pwd').value;
|
|
var confirmPwd = document.getElementById('confirm_pwd').value;
|
|
|
|
// Current password is required (cannot be empty)
|
|
if (!currentPwd || currentPwd.trim() === "") {
|
|
alert("Current password is required");
|
|
return false;
|
|
}
|
|
|
|
// Validate current password contains only printable characters
|
|
if (!isValidPrintableString(currentPwd)) {
|
|
alert("Current password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
|
return false;
|
|
}
|
|
|
|
// New password is required (cannot be empty)
|
|
if (!newPwd || newPwd.trim() === "") {
|
|
alert("New password is required");
|
|
return false;
|
|
}
|
|
|
|
// Validate new password contains only printable characters
|
|
if (!isValidPrintableString(newPwd)) {
|
|
alert("New password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
|
return false;
|
|
}
|
|
|
|
// Validate new password length (max 16 chars)
|
|
if (newPwd.length > 16) {
|
|
alert("New password must be no more than 16 characters");
|
|
return false;
|
|
}
|
|
|
|
// Validate new password length
|
|
if (newPwd.length < 6) {
|
|
alert("New password must be at least 6 characters");
|
|
return false;
|
|
}
|
|
|
|
// Confirm password must match new password
|
|
if (newPwd !== confirmPwd) {
|
|
alert("New passwords do not match");
|
|
return false;
|
|
}
|
|
|
|
// Validate confirm password contains only printable characters
|
|
if (!isValidPrintableString(confirmPwd)) {
|
|
alert("Confirm password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
|
return false;
|
|
}
|
|
|
|
// Validate confirm password length (max 16 chars)
|
|
if (confirmPwd.length > 16) {
|
|
alert("Confirm password must be no more than 16 characters");
|
|
return false;
|
|
}
|
|
|
|
// Validate new username if provided
|
|
if (newUsername && newUsername.trim() !== "") {
|
|
// Validate new username contains only printable characters
|
|
if (!isValidPrintableString(newUsername)) {
|
|
alert("New username contains invalid characters. Only printable characters (excluding space) are allowed.");
|
|
return false;
|
|
}
|
|
|
|
// Validate new username length (max 16 chars)
|
|
if (newUsername.length > 16) {
|
|
alert("New username must be no more than 16 characters");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true; // Allows the form to submit
|
|
}
|
|
|
|
// Form submission handler using fetch API
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var accountForm = document.getElementById('accountForm');
|
|
if (accountForm) {
|
|
accountForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
if (!validateAccountForm()) return;
|
|
|
|
var formData = new URLSearchParams({
|
|
Username: document.getElementById('current_user').value,
|
|
OldPassword: document.getElementById('current_pwd').value,
|
|
NewUsername: document.getElementById('new_user').value,
|
|
NewPassword: document.getElementById('new_pwd').value,
|
|
ConfirmPassword: document.getElementById('confirm_pwd').value
|
|
});
|
|
|
|
fetch('login.cgi?action=change_account', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert("Update successful! Please login again.");
|
|
closeAccountModal();
|
|
// Redirect to login page after 1.5 seconds
|
|
setTimeout(function() {
|
|
window.location.href = 'login.cgi?logout=1';
|
|
}, 1500);
|
|
} else {
|
|
alert(data.error || "Update failed");
|
|
}
|
|
})
|
|
.catch(function(err) {
|
|
alert("Network error: " + err);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
// Optional: Closes the modal if the user clicks the dark background outside the box
|
|
window.onclick = function(event) {
|
|
var modal = document.getElementById('accountModal');
|
|
if (event.target == modal) {
|
|
closeAccountModal();
|
|
}
|
|
}
|
|
|
|
</script>
|
|
</head>
|
|
|
|
<body onload="refresh_show()">
|
|
|
|
<div class="app-layout">
|
|
<aside class="app-sidebar">
|
|
<ul class="items">
|
|
<li><a href="status_info.html" title="Status">Status</a></li>
|
|
<li><a href="sys_set.html" title="Settings">Settings</a></li>
|
|
<li><a href="sys_rf.html" title="RF Control">RF Control</a></li>
|
|
<li><a href="sys_psip.html" title="TSID&PSIP">TSID&PSIP</a></li>
|
|
<li><a href="sys_ts.html" title="TSoIP">TSoIP</a></li>
|
|
<li><a href="sys_spectrum.html" title="Spectrum">Spectrum</a></li>
|
|
<li class="active"><a href="log_output.html" title="Log">Log</a></li>
|
|
</ul>
|
|
<div class="sidebar-footer">
|
|
<h4>Anywave Broadcast Inc.</h4>
|
|
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
|
</div>
|
|
</aside>
|
|
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
|
|
|
<header class="app-header">
|
|
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="3" y1="12" x2="21" y2="12"></line>
|
|
<line x1="3" y1="6" x2="21" y2="6"></line>
|
|
<line x1="3" y1="18" x2="21" y2="18"></line>
|
|
</svg>
|
|
</button>
|
|
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
|
<h2 id="webtitle_header"><span></span></h2>
|
|
<h3>
|
|
<div class="dropdown">
|
|
<button class="dropbtn-modern">Admin ▾</button>
|
|
<div class="dropdown-content">
|
|
<a href="#" onclick="openAccountModal(); return false;">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="3"></circle>
|
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06-.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
|
</svg>
|
|
Account Settings
|
|
</a>
|
|
<a href="login.cgi?logout=1">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
|
<polyline points="16 17 21 12 16 7"></polyline>
|
|
<line x1="21" y1="12" x2="9" y2="12"></line>
|
|
</svg>
|
|
Logout
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</h3>
|
|
</header>
|
|
|
|
<!-- Fixed Dashboard Summary - Top of page, under header -->
|
|
<div class="dashboard-fixed">
|
|
<div class="summary-dashboard">
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-neutral" id="dot_freq" aria-hidden="true"></span>
|
|
<span class="summary-label">Frequency</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-neutral" id="sum_freq">--</span>
|
|
<span class="summary-unit">MHz</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-ok" id="dot_snr" aria-hidden="true"></span>
|
|
<span class="summary-label">SNR</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-ok" id="sum_snr">--</span>
|
|
<span class="summary-unit">dB</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-ok" id="dot_uimd" aria-hidden="true"></span>
|
|
<span class="summary-label">UIMD</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-ok" id="sum_uimd">--</span>
|
|
<span class="summary-unit">dBc</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-ok" id="dot_limd" aria-hidden="true"></span>
|
|
<span class="summary-label">LIMD</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-ok" id="sum_limd">--</span>
|
|
<span class="summary-unit">dBc</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-off" id="dot_rf" aria-hidden="true"></span>
|
|
<span class="summary-label">RF Switch</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-muted" id="sum_rf">--</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-ok" id="dot_outpow" aria-hidden="true"></span>
|
|
<span class="summary-label">Output Power</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-ok" id="sum_outpow">--</span>
|
|
<span class="summary-unit">dBm</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-neutral" id="dot_input" aria-hidden="true"></span>
|
|
<span class="summary-label">Input Source</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-neutral" id="sum_input">--</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-neutral" id="dot_input_status" aria-hidden="true"></span>
|
|
<span class="summary-label">Input Status</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-neutral" id="sum_input_status">--</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-neutral" id="dot_bitrate" aria-hidden="true"></span>
|
|
<span class="summary-label">Bitrate</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-neutral" id="sum_bitrate">--</span>
|
|
<span class="summary-unit">Mbps</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-ok" id="dot_temp" aria-hidden="true"></span>
|
|
<span class="summary-label">Temperature</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-ok" id="sum_temp">--</span>
|
|
<span class="summary-unit">°F</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-off" id="dot_agc" aria-hidden="true"></span>
|
|
<span class="summary-label">AGC</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-muted" id="sum_agc">--</span>
|
|
</div>
|
|
</div>
|
|
<div class="summary-card">
|
|
<div class="summary-label-row">
|
|
<span class="status-dot status-neutral" id="dot_control" aria-hidden="true"></span>
|
|
<span class="summary-label">Control</span>
|
|
</div>
|
|
<div class="summary-value-wrapper">
|
|
<span class="summary-value value-neutral" id="sum_control">--</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<main class="app-main">
|
|
<h2>Output Log</h2>
|
|
<div class="box log-export-box">
|
|
<table>
|
|
<tr>
|
|
<td class="log-export-label">
|
|
Export System Log
|
|
</td>
|
|
<td class="log-export-actions">
|
|
<input type="button" class="btn-modern" id="get_log_btn" alt="GET" value="Get" disabled onclick="return Get_Log_File();">
|
|
<a href="/module_log.zip" download="module_log.zip">
|
|
<input type="button" class="btn-modern" style="visibility:hidden;" id="id_download" alt="DOWNLOAD" value="Download">
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<div id="accountModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3>Account Settings</h3>
|
|
<span class="close" onclick="closeAccountModal()">×</span>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="accountForm" method="post" action="login.cgi?action=change_account" onsubmit="return validateAccountForm()">
|
|
<table class="modal-table">
|
|
<tr>
|
|
<td>Current Username</td>
|
|
<td><input type="text" id="current_user" name="current_user" readonly></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Current Password</td>
|
|
<td><input type="password" id="current_pwd" name="current_pwd" required></td>
|
|
</tr>
|
|
<tr>
|
|
<td>New Username</td>
|
|
<td><input type="text" id="new_user" name="new_user"></td>
|
|
</tr>
|
|
<tr>
|
|
<td>New Password</td>
|
|
<td><input type="password" id="new_pwd" name="new_pwd"></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Confirm Password</td>
|
|
<td><input type="password" id="confirm_pwd" name="confirm_pwd"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="modal-footer">
|
|
<input type="button" class="btn-modern" style="background-color: #64748b;" value="Cancel" onclick="closeAccountModal()">
|
|
<input type="submit" class="btn-modern" value="Save Changes">
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function toggleSidebar(){
|
|
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
|
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|