repo reorg

This commit is contained in:
Tom Mortensen
2023-06-02 12:49:33 -07:00
parent 25e934f0a7
commit f9ec00b488
699 changed files with 6700 additions and 68456 deletions
+4
View File
@@ -0,0 +1,4 @@
Menu="Tools:90"
Type="menu"
Title="About"
Tag="question-circle-o"
+34
View File
@@ -0,0 +1,34 @@
Menu="Tasks:80"
Name="Apps"
Code="e942"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
div.notice{margin:150px 0 20px 0}
</style>
<script>
function installPlugin(file) {
openPlugin("plugin install "+file,"_(Install Plugin)_","","refresh");
}
</script>
<div class="notice">_(Click **Install** to download and install the **Community Applications** plugin)_</div>
<form markdown="1" name="ca_install" method="POST" target="progressFrame">
<input type="hidden" name="file" value="https://raw.githubusercontent.com/Squidly271/community.applications/master/plugins/community.applications.plg">
&nbsp;
: <input type="button" value="_(Install)_" onclick="installPlugin(this.form.file.value)">
</form>
+81
View File
@@ -0,0 +1,81 @@
Menu="Main:1"
Title="Array Devices"
Tag="database"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function toggle_state(device,name,action) {
var button = null;
if (name) {
var group = name.replace(/(\d+|\*)$/,'');
if (name.slice(-1)!='*') {
$('#dev-'+name).removeClass('fa-circle fa-square fa-warning fa-times').addClass('fa-refresh fa-spin');
} else {
if (group=='array') {
$('[id^="dev-parity"]').removeClass('fa-circle fa-square fa-warning fa-times').addClass('fa-refresh fa-spin');
$('[id^="dev-disk"]').removeClass('fa-circle fa-square fa-warning fa-times').addClass('fa-refresh fa-spin');
} else {
$('[id^="dev-'+group+'"]').removeClass('fa-circle fa-square fa-warning fa-times').addClass('fa-refresh fa-spin');
}
}
} else if (device!='Clear') {
$('[id^="dev-"]').removeClass('fa-circle fa-square fa-warning fa-times').addClass('fa-refresh fa-spin');
button = '[id^=button-]';
}
devices.stop();
$.post('/webGui/include/ToggleState.php',{device:device,name:name,action:action,state:'<?=$var['mdState']?>',csrf:'<?=$var['csrf_token']?>'},function(){setTimeout(function(){devices.start();},1000);if (button) $(button).prop('disabled',false);});
}
function display_diskio() {
if ($.cookie('diskio')===undefined) {
$('span.number').show(); $('span.diskio').hide();
} else {
$('span.diskio').show(); $('span.number').hide();
}
}
function toggle_diskio(init) {
if (!init) {
if ($.cookie('diskio')===undefined) $.cookie('diskio','diskio',{expires:3650}); else $.removeCookie('diskio');
}
if ($.cookie('diskio')===undefined) {
$('i.toggle').removeClass('fa-tachometer').addClass('fa-list');
} else {
$('i.toggle').removeClass('fa-list').addClass('fa-tachometer');
}
display_diskio();
}
<?if (_var($var,'fsState')=="Started"):?>
$('#tab1').bind({click:function() {$('i.toggle').show('slow');}});
<?endif;?>
</script>
<table class="disk_status wide">
<thead><tr><td>_(Device)_</td><td>_(Identification)_</td><td>_(Temp)_.</td><td>_(Reads)_</td><td>_(Writes)_</td><td>_(Errors)_</td><td>_(FS)_</td><td>_(Size)_</td><td>_(Used)_</td><td>_(Free)_</td></tr></thead>
<tbody id="array_devices">
<?
foreach ($disks as $disk):
if (_var($disk,'type')=='Parity' or _var($disk,'type')=='Data')
echo "<tr><td colspan='11'>&nbsp;</td></tr>";
endforeach;
if (_var($display,'total')) echo "<tr class='tr_last'><td colspan='11'>&nbsp;</td></tr>";
?>
</tbody>
</table>
:main_array_devices_help:
<?if (_var($var,'fsState')=="Stopped"):?>
<div></div>
:main_slots_help:
<?endif;?>
+700
View File
@@ -0,0 +1,700 @@
Menu="Main:5"
Title="Array Operation"
Tag="snowflake-o"
Nchan="device_list,disk_load,parity_list"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$keyfile = file_exists(_var($var,'luksKeyfile'));
$missing = file_exists('/var/tmp/missing.tmp');
$encrypt = false;
$spot = _var($var,'mdResyncPos',0)>0;
/* only one of $present, $missing, or $wrong will be true, or all will be false */
$forced = $present = $wrong = false;
foreach ($disks as $disk) {
if (!isset($disk['fsType'])) continue;
if (strpos(_var($disk,'fsType'),'luks:')!==false || (_var($disk,'fsType')=='auto' && (strpos(_var($var,'defaultFsType'),'luks:')!==false || _var($disk,'luksState',0)==2 || _var($disk,'luksState',0)==3))) {
$encrypt = true;
if (_var($disk,'luksState',0)==0) $forced = true;
if (_var($disk,'luksState',0)==1) $present = true;
if (_var($disk,'luksState',0)==2) $missing = true;
if (_var($disk,'luksState',0)==3) $wrong = true;
}
}
if ($forced && ($present || $missing || $wrong)) $forced = false;
function check_encryption() {
global $forced, $missing, $wrong;
if ($forced) $status = _('Enter new key');
elseif ($missing) $status = _('Missing key');
elseif ($wrong) $status = _('Wrong key');
else return;
echo "<tr><td></td><td class='gap'>",_('Encryption status').":</td><td><span class='red-text'>$status</span><span id='pass'><input name='luksReformat' type='checkbox' onchange='selectInput(this.form)'>permit reformat</span></td></tr>";
echo "<tr><td></td><td class='gap'>",_('Encryption input').":</td><td>";
echo "<select name='input' size='1' onchange='selectInput(this.form)'>";
echo mk_option(1,'text',_('Passphrase'));
echo mk_option(1,'file',_('Keyfile'));
echo "</select></td></tr>";
echo "<tr id='text'><td></td><td class='gap'>",_('Passphrase'),":</td><td><input type='password' name='text' maxlength='512' value='' onkeyup='selectInput(this.form)' placeholder=\""._('use printable characters only')."\"><input name='showPass' type='checkbox' onchange='selectInput(this.form)'>"._('show passphrase')."</td></tr>";
echo "<tr id='copy'><td></td><td class='gap'>",_('Retype passphrase'),":</td><td><input type='password' name='copy' maxlength='512' value='' onkeyup='selectInput(this.form)'></td></tr>";
echo "<tr id='file'><td></td><td class='gap'>",_('Keyfile'),":</td><td><input type='file' name='local' onchange='getFileContent(event,this.form)'></td></tr>";
}
function maintenance_mode() {
echo "<tr>";
echo "<td></td>";
echo "<td><input type='checkbox' name='startMode' value='Maintenance'>",_('Maintenance mode'),"</td>";
echo "<td><b>",_('Maintenance mode'),"</b> - ",_('if checked, Start array but do not mount disks'),"</td>";
echo "</tr>";
}
function status_indicator() {
global $var;
switch (_var($var,'mdColor')) {
case 'green-on': $orb = 'circle'; $color = 'green'; $help =_('Started, array protected'); break;
case 'green-blink': $orb = 'circle'; $color = 'grey'; $help = _('Stopped'); break;
case 'yellow-on': $orb = 'warning'; $color = 'yellow'; $help = _('Started, array unprotected'); break;
case 'yellow-blink': $orb = 'warning'; $color = 'grey'; $help = _('Stopped'); break;
}
echo "<a class='info'><i class='fa fa-$orb orb $color-orb'></i><span>$help</span></a>";
}
function missing_cache() {
global $disks;
$missing = false;
foreach (cache_filter($disks) as $disk) $missing |= (strpos(_var($disk,'status'),'_MISSING')!==false);
return $missing;
}
function resync($d) {
return in_array($d,['P','Q']) ? 'Parity-Sync' : 'Data-Rebuild';
}
function print_error($error) {
return sprintf(_('Finding **%s** error'.($error==1?'':'s')),$error?:'0');
}
?>
<style>
tr#copy,tr#file{display:none}
td.gap{padding-left:26px!important}
td.wrap{white-space:normal!important}
span#pass{display:none;margin-left:20px}
input[type=checkbox]{margin-left:0}
</style>
<script>
var ctrl = '<span class="status <?=$tabbed?"":"vhshift"?>"><a style="cursor:pointer" class="tooltip_diskio" title="_(Toggle reads/writes display)_" onclick="toggle_diskio();return false"><i class="toggle fa"></i></a></span>';
function base64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
function selectInput(form) {
<?if ($wrong && $keyfile):?>
form.input.value = 'file';
form.input.disabled = true;
<?endif;?>
if (form.input.value=='text') {
form.file.value = '';
form.local.value = '';
<?if ($forced):?>
$('#text').show();
$('#copy').show();
$('#pass').hide();
$('input[name="confirmStart"]').prop('disabled',true);
<?elseif ($missing):?>
$('#text').show();
$('#copy').hide();
$('#pass').hide();
$('input[name="confirmStart"]').prop('disabled',true);
<?elseif ($wrong):?>
$('#text').show();
if ($('input[name="luksReformat"]').prop('checked')) $('#copy').show(); else $('#copy').hide();
$('#pass').show();
$('input[name="confirmStart"]').prop('disabled',true);
<?endif;?>
$('#file').hide();
$('input[name="text"],input[name="copy"]').attr('type',$('input[name="showPass"]').prop('checked')?'text':'password');
var item = $('input[name="confirmStart"]').length ? $('input[name="confirmStart"]') : $('#cmdStart');
item.prop('disabled',$('#copy').is(':visible') ? (form.text.value!=form.copy.value || form.text.value=='') : form.text.value=='');
} else {
form.text.value = '';
form.copy.value = '';
$('#text').hide();
$('#copy').hide();
$('#file').show();
<?if ($wrong):?>
$('#pass').show();
<?else:?>
$('#pass').hide();
<?endif;?>
var item = $('input[name="confirmStart"]').length ? $('input[name="confirmStart"]') : $('#cmdStart');
item.prop('disabled',!form.file.value);
}
}
function getFileContent(event,form) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){form.file.value=reader.result;selectInput(form);};
reader.readAsDataURL(input.files[0]);
}
function prepareInput(form,button) {
if (button) button.disabled = true;
$.post('/webGui/include/Report.php',{cmd:'state',pools:'<?=implode(',',$pools)?>'},function(state) {
if (state.length==0) {
$(form).append('<input type="hidden" name="cmdStart" value="Start">');
if (form.input === undefined) {
form.submit();
return;
}
form.input.disabled = true;
form.local.disabled = true;
form.file.disabled = true;
form.text.disabled = true;
form.copy.disabled = true;
if (form.text.value) {
var valid = new RegExp('^[ -~]+$');
if (valid.test(form.text.value)) {
$(form).append('<input type="hidden" name="luksKey" value="'+base64(form.text.value)+'">');
form.submit();
} else {
form.input.disabled = false;
form.local.disabled = false;
form.file.disabled = false;
form.text.disabled = false;
form.copy.disabled = false;
swal({title:"_(Printable Characters Only)_",text:"_(Use **ASCII** characters from space ' ' to tilde '~')_<br>_(Otherwise use the **keyfile** method for UTF8 input)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});
}
return;
}
var data = {};
data['#file'] = 'unused';
data['#include'] = 'webGui/include/KeyUpload.php';
data['file'] = form.file.value;
$.post('/update.php',data,function(){form.submit();});
} else {
swal({title:"_(Wrong Pool State)_",text:state,type:'error',html:true,confirmButtonText:"_(Ok)_"});
}
});
}
function parityWarning(form) {
if (form.md_invalidslot.checked) {
<?if (strpos(_var($disks['parity2'],'status'),'_NP')===false):?>
var text = "_(*Dual parity* valid requires **ALL** disks in their original slots)_";
<?else:?>
var text = "_(*Parity valid* requires **ALL** disks to have their original content)_";
<?endif;?>
} else {
var text = "_(*Parity* disk(s) content will be overwritten)_";
}
swal({title:"_(Proceed to start)_",text:text,html:true,type:'warning',showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){prepareInput(form);});
}
function tab0() {
$.removeCookie('one');
$.cookie('tab','tab0');
}
function stopArray(form) {
$(form).append('<input type="hidden" name="cmdStop" value="Stop">');
<?if ($confirm['stop']):?>
swal({title:"_(Proceed)_?",text:"_(This will stop the array)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) form.submit(); else $('input[name="cmdStop"]').remove();});
<?else:?>
form.submit();
<?endif;?>
}
function stopParity(form,text) {
$(form).append('<input type="hidden" name="cmdCheckCancel" value="">');
<?if ($confirm['stop']):?>
swal({title:"_(Proceed)_?",text:"_(This will stop the running operation)_: "+text,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) form.submit(); else $('input[name="cmdCheckCancel"]').remove();});
<?else:?>
form.submit();
<?endif;?>
}
function pauseParity(form) {
$.post('/webGui/include/ParityControl.php',{action:'pause'},function(){
$('#pauseButton').val("_(Resume)_").prop('disabled',true).prop('onclick',null).off('click').click(function(){resumeParity(form);});
$(form).append('<input type="hidden" name="cmdCheckPause" value="">');
form.submit();
});
}
function resumeParity(form) {
$.post('/webGui/include/ParityControl.php',{action:'resume'},function(){
$('#pauseButton').val("_(Pause)_").prop('disabled',true).prop('onclick',null).off('click').click(function(){pauseParity(form);});
$(form).append('<input type="hidden" name="cmdCheckResume" value="">');
form.submit();
});
}
function parityHistory() {
openChanges("parity_history", "_(Parity Operation History)_", "phistory");
}
function shutdown_now(form,cmd) {
$(form).append('<input type="hidden" name="cmd" value="'+cmd+'">');
<?if ($confirm['down']):?>
switch (cmd) {
case 'reboot': var text = "_(This will reboot the system)_"; break;
case 'shutdown': var text = "_(This will shutdown the system)_"; break;
}
swal({title:"_(Proceed)_?",text:text,type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(p){if (p) form.submit(); else $('input[name="cmd"]').remove();});
<?else:?>
form.submit();
<?endif;?>
}
function toggleApply(checked) {
$('input[name="#apply"]').prop('disabled',!checked);
}
<?if ($tabbed):?>
$('.tabs').append(ctrl);
if ($.cookie('tab')=='tab0') $('i.toggle').hide();
$('#tab'+$('input[name$="tabs"]').length).click(function(){tab0(); $('i.toggle').hide('slow');});
<?else:?>
$('div[class=title]:not(":last, .disable_diskio")').each(function(){$(this).append(ctrl);});
<?endif;?>
$('.tooltip_diskio').tooltipster({delay:100,trigger:'custom',triggerOpen:{mouseenter:true},triggerClose:{click:false,scroll:true,mouseleave:true}});
toggle_diskio(true);
<?if (_var($var,'fsState')=='Started'):?>
var mymonitor = new NchanSubscriber('/sub/mymonitor',{subscriber:'websocket'});
mymonitor.on('message', function(state) {
switch (state) {
case '0': // normal operation
$('#stop-button').prop('disabled',false);
$('#stop-text').html("");
<?if (_var($var,'fsState')!="Stopped"):?>
$('#spinup-button').prop('disabled',false);
$('#spindown-button').prop('disabled',false);
<?endif;?>
<?if (_var($var,'shareUser')=='e' && $pool_devices):?>
$('#mover-button').prop('disabled',false);
$('#mover-text').html("<b>_(Move)_</b> _(will immediately invoke the Mover)_.&nbsp;<a href=\"/Main/Settings/Scheduler\"<?if($tabbed):?> onclick=\"$.cookie('one','tab2')\"<?endif;?>>(_(Schedule)_)</a>");
<?endif;?>
break;
case '1': // parity running
$('#stop-button').prop('disabled',true);
$('#stop-text').html("<br><small>_(Disabled)_ -- _(Parity operation is running)_</small>");
<?if (_var($var,'fsState')!="Stopped" && _var($var,'mdResync',0)>0):?>
$('#spinup-button').prop('disabled',true);
$('#spindown-button').prop('disabled',true);
<?endif;?>
<?if (_var($var,'shareUser')=='e' && $pool_devices):?>
$('#mover-button').prop('disabled',true);
$('#mover-text').html("_(Disabled)_ -- _(Parity operation is running)_");
<?endif;?>
break;
case '2': // mover running
$('#stop-button').prop('disabled',true);
$('#stop-text').html("<br><small>_(Disabled)_ -- _(Mover is running)_</small>");
<?if (_var($var,'shareUser')=='e' && $pool_devices):?>
$('#mover-button').prop('disabled',true);
$('#mover-text').html("_(Disabled)_ - _(Mover is running)_.");
<?endif;?>
break;
case '3': // btrfs running
$('#stop-button').prop('disabled',true);
$('#stop-text').html("<br><small>_(Disabled)_ -- _(BTRFS operation is running)_</small>");
<?if (_var($var,'shareUser')=='e' && $pool_devices):?>
$('#mover-button').prop('disabled',true);
$('#mover-text').html("_(Disabled)_ -- _(BTRFS operation is running)_");
<?endif;?>
break;
}
});
mymonitor.start();
<?endif;?>
var arraymonitor = new NchanSubscriber('/sub/arraymonitor',{subscriber:'websocket'});
arraymonitor.on('message', function(state) {
if (state==1 && !timers.arraymonitor) timers.arraymonitor = setTimeout(refresh,1250);
});
var devices = new NchanSubscriber('/sub/devices<?=$spot?",parity":""?>',{subscriber:'websocket'});
devices.on('message', function(msg,meta) {
switch (<?if($spot):?>meta.id.channel()<?else:?>0<?endif;?>) {
case 0:
// array + pool + ua devices
var tables = msg.split('\0');
// get array state
var stopped = tables.pop();
for (var n=0; n < tables.length; n++) {
// get table name and content
var table = tables[n].split('\n');
$('#'+table[0]).html(table[1]);
}
display_diskio();
// stop updating when array is stopped
if (stopped==1) {
<?if (_var($var,'fsState')=='Started'):?>
setTimeout(refresh,0);
<?else:?>
if (!timers.stopped) timers.stopped = setTimeout(function(){devices.stop(); arraymonitor.start();},1000);
<?endif;?>
}
break;
case 1:
// running parity status
$.each(msg.split(';'),function(k,v) {if ($('#line'+k).length>0) $('#line'+k).html(v);});
// button control
if ($('#pauseButton').length>0 && $('#pauseButton').prop('disabled')==false) {
if (!msg && $('#cancelButton').length>0 && $('#cancelButton').val()=="_(Cancel)_") {
$('#cancelButton').val("_(Done)_").prop('onclick',null).off('click').click(function(){refresh();});
$('#pauseButton').prop('disabled',true);
$('#cancelText').html('');
$('#line4').html("_(completed)_");
} else {
var form = document.arrayOps;
if ($('#pauseButton').val()=="_(Pause)_" && msg.search("_(paused)_")!=-1) {
$('#pauseButton').val("_(Resume)_").prop('onclick',null).off('click').click(function(){resumeParity(form);});
} else if ($('#pauseButton').val()=="_(Resume)_" && msg.search("_(paused)_")==-1) {
$('#pauseButton').val("_(Pause)_").prop('onclick',null).off('click').click(function(){pauseParity(form);});
}
}
}
break;
}
});
devices.start();
<?if (substr(_var($var,'fsState'),-3)=='ing'):?>
var fsState = new NchanSubscriber('/sub/fsState',{subscriber:'websocket'});
fsState.on('message', function(msg) {
switch (msg) {
case 'stop':
if (!timers.fsState) timers.fsState = setTimeout(refresh,1250);
break;
default:
if (msg) $('#fsState').html(msg);
break;
}
});
fsState.start();
<?elseif ($spot):?>
setTimeout(function(){$('#pauseButton').prop('disabled',false);$('#cancelButton').prop('disabled',false);},250);
<?else:?>
var paritymonitor = new NchanSubscriber('/sub/paritymonitor',{subscriber:'websocket'});
paritymonitor.on('message', function(busy){if (busy==1) refresh();});
setTimeout(function(){paritymonitor.start();},5000);
<?endif;?>
$(function(){
var form = document.arrayOps;
if (form.input !== undefined) selectInput(form);
});
function formatWarning(val) {
if (val==true) {
swal({
title:"_(Format Unmountable disks)_",
text: "_(Create an empty file system on the disks shown as **Unmountable** discarding all data currently on the disks and update parity to reflect this)_. "+
"_(This is typically done when a new disk is added to the array to get it ready for files to be written to it)_.<br>"+
"<p><br>**_(WARNING)_**"+
"<p>_(A format is **NEVER** part of a data recovery or disk rebuild process and if done in such circumstances will normally lead to loss of all data on the disks being formatted)_.",
type: "warning",
html: true,
confirmButtonText:"_(Ok)_"
});
}
}
</script>
<form name="arrayOps" method="POST" action="/update.htm" target="progressFrame">
<input type="hidden" name="startState" value="<?=htmlspecialchars(_var($var,'mdState'))?>">
<input type="hidden" name="file" value="">
<table markdown="1" class="array_status">
<?switch (_var($var,'fsState')):
case "Started":?>
<tr><td><?status_indicator()?>**_(Started)_<?=((_var($var,'startMode')=='Maintenance')?' - _(Maintenance Mode)_':'')?>**</td>
<td><input type="button" id="stop-button" value="_(Stop)_" onclick="stopArray(this.form)"></td>
<td>**_(Stop)_** _(will take the array off-line)_.<span id="stop-text"></span></td></tr>
<? if (_var($var,'fsNumUnmountable',0)>0):?>
<tr><td>**<?=_('Unmountable disk'.(_var($var,'fsNumUnmountable',0)==1?'':'s').' present')?>:**<br>
<? $cache = [];
foreach ($disks as $disk) if (substr(_var($disk,'fsStatus'),0,11)=='Unmountable' || in_array(prefix(_var($disk,'name')),$cache)) {
if (strlen(_var($disk,'id'))) echo "<span class='blue-text'>".my_disk(_var($disk,'name'))."</span> &bullet; ".my_id(_var($disk,'id'))." ("._var($disk,'device').")<br>";
if (in_array(_var($disk,'name'),$pools)) $cache[] = $disk['name'];
}
?> </td><td><input type="submit" id="btnFormat" name="cmdFormat" value="_(Format)_" disabled><input type="hidden" name="unmountable_mask" value="<?=_var($var,'fsUnmountableMask')?>"></td>
<td>**_(Format)_** _(will create a file system in all **Unmountable** disks)_.<br>
<a class="info none img nohand"><input type="checkbox" name="confirmFormat" value="OFF" onclick="formatWarning(this.checked),$('#btnFormat').prop('disabled',!arrayOps.confirmFormat.checked)">
<small>_(Yes, I want to do this)_</small></a>
</td></tr>
<? endif;
$action = preg_split('/\s+/',_var($var,'mdResyncAction'));
if (!$spot):
if ($action[0]=="recon"):
$resync = resync($action[1]);
?> <tr><td></td><td><input type="submit" name="cmdCheckSync" value="_(Sync)_"></td><td>**<?=_('Sync')?>** <?=_("will start **$resync**")?>.</td></tr>
<? elseif ($action[0]=="clear"):?>
<tr><td></td><td><input type="submit" name="cmdCheckClear" value="_(Clear)_"></td><td>**_(Clear)_** _(will start **Disk-Clear** of new data disk(s))_.</td></tr>
<? else:
if ($action[0]=="check" && count($action)>1):?>
<tr><td>_(Parity is valid)_.</td><td><input type="submit" name="cmdCheck" value="_(Check)_"></td><td>**_(Check)_** _(will start **Parity-Check**)_.&nbsp;<a href="/Main/Settings/Scheduler"<?if ($tabbed):?> onclick="$.cookie('one','tab1')"<?endif;?>>(_(Schedule)_)</a>
<br><input type="checkbox" name="optionCorrect" value="correct" checked><small>_(Write corrections to parity)_</small></td></tr>
<? elseif ($action[0]=="check"):?>
<tr><td></td><td><input type="submit" name="cmdCheck" value="_(Check)_"></td><td>**_(Check)_** _(will start **Read-Check** of all array disks)_.</td></tr>
<? endif;?>
<tr><td></td><td><input type="button" value="_(History)_" onclick="parityHistory()"></td>
<? [$date,$duration,$speed,$status,$error,$action,$size] = last_parity_log();
if (_var($var,'sbSyncExit',0)!=0):?>
<td class="wrap"><?=sprintf(_('Last check incomplete on **%s**'),_(my_time(_var($var,'sbSynced2',0)).day_count(_var($var,'sbSynced2',0)),0))?><?if (_var($var,'sbSynced2')):?>
<br><i class="fa fa-fw fa-dot-circle-o"></i> _(Error code)_: <?=my_error(_var($var,'sbSyncExit'))?>
<br><i class="fa fa-fw fa-search"></i> <?=print_error(_var($var,'sbSyncErrs',0))?><?endif;?></td></tr>
<? elseif (_var($var,'sbSynced',0)==0):
if ($status==0):?>
<td class="wrap"><?=sprintf(_('Last checked on **%s**'),_(my_time($date).day_count($date),0))?>
<br><i class="fa fa-fw fa-clock-o"></i> _(Duration)_: <?=my_check($duration,$speed)?>
<br><i class="fa fa-fw fa-search"></i> <?=print_error($error)?></td></tr>
<? else:?>
<td class="wrap"><?=sprintf(_('Last check incomplete on **%s**'),_(my_time($date).day_count($date),0))?>
<br><i class="fa fa-fw fa-dot-circle-o"></i> _(Error code)_: <?=my_error($status)?>
<br><i class="fa fa-fw fa-search"></i> <?=print_error($error)?></td></tr>
<? endif;
elseif (_var($var,'sbSynced2',0)==0):
if ($status==0):?>
<td class="wrap"><?=sprintf(_('Last checked on **%s**'),_(my_time(_var($var,'sbSynced',0)).day_count(_var($var,'sbSynced',0)),0))?>
<br><i class="fa fa-fw fa-clock-o"></i> _(Duration)_: <?=my_check($duration,$speed)?>
<br><i class="fa fa-fw fa-search"></i> <?=print_error($error)?></td></tr>
<? else:?>
<td class="wrap"><?=sprintf(_('Last check incomplete on **%s**'),_(my_time(_var($var,'sbSynced',0)).day_count(_var($var,'sbSynced',0)),0))?>
<br><i class="fa fa-fw fa-dot-circle-o"></i> _(Error code)_: <?=my_error($status)?>
<br><i class="fa fa-fw fa-search"></i> <?=print_error($error)?></td></tr>
<? endif;
else:?>
<td class="wrap"><?=sprintf(_('Last check completed on **%s**'),_(my_time(_var($var,'sbSynced2',0)).day_count(_var($var,'sbSynced2',0)),0))?>
<br><i class="fa fa-fw fa-clock-o"></i> _(Duration)_: <?=my_check($duration,$speed)?>
<br><i class="fa fa-fw fa-search"></i> <?=print_error(_var($var,'sbSyncErrs',0))?></td></tr>
<? endif;
endif;
else:
if ($action[0]=="recon"):
$resync = resync($action[1]);
?> <tr><td><?=_("$resync in progress")?>.</td><td>
<input type="button" id="pauseButton"<?if (_var($var,'mdResync')):?> value="_(Pause)_" onclick="pauseParity(this.form)"<?else:?> value="_(Resume)_" onclick="resumeParity(this.form)"<?endif;?> disabled>
<input type="button" id="cancelButton" value="_(Cancel)_" onclick="stopParity(this.form,'<?=$resync?>')" disabled></td>
<td id="cancelText"><?if (_var($var,'mdResync')):?>**<?=_('Pause')?>** <?=_("will pause $resync")?>.<?else:?>**<?=_('Resume')?>** <?=_("will resume $resync")?>.<?endif;?><br>**<?=_('Cancel')?>** <?=_("will stop $resync")?>.
<br>_(WARNING: canceling may leave the array unprotected)_!</td></tr>
<? elseif ($action[0]=="clear"):?>
<tr><td>_(Disk-Clear in progress)_.</td><td>
<input type="button" id="pauseButton"<?if (_var($var,'mdResync')):?> value="_(Pause)_" onclick="pauseParity(this.form)"<?else:?> value="_(Resume)_" onclick="resumeParity(this.form)"<?endif;?> disabled>
<input type="button" id="cancelButton" value="_(Cancel)_" onclick="stopParity(this.form,'Disk-Clear')" disabled></td>
<td id="cancelText"><?if (_var($var,'mdResync')):?>**_(Pause)_** _(will pause Disk-Clear)_.<?else:?>**_(Resume)_** _(will resume Disk-Clear)_.<?endif;?><br>**_(Cancel)_** _(will stop Disk-Clear)_.</td></tr>
<? elseif ($action[0]=="check" && count($action)>1):?>
<tr><td>_(Parity-Check in progress)_.</td><td>
<input type="button" id="pauseButton"<?if (_var($var,'mdResync')):?> value="_(Pause)_" onclick="pauseParity(this.form)"<?else:?> value="_(Resume)_" onclick="resumeParity(this.form)"<?endif;?> disabled>
<input type="button" id="cancelButton" value="_(Cancel)_" onclick="stopParity(this.form,'Parity-Check')" disabled></td>
<td id="cancelText"><?if (_var($var,'mdResync')):?>**_(Pause)_** _(will pause Parity-Check)_.<?else:?>**_(Resume)_** _(will resume Parity-Check)_.<?endif;?><br>**_(Cancel)_** _(will stop Parity-Check)_.</td></tr>
<? elseif ($action[0]=="check"):?>
<tr><td>_(Read-Check in progress)_.</td><td>
<input type="button" id="pauseButton"<?if (_var($var,'mdResync')):?> value="_(Pause)_" onclick="pauseParity(this.form)"<?else:?> value="_(Resume)_" onclick="resumeParity(this.form)"<?endif;?> disabled>
<input type="button" id="cancelButton" value="_(Cancel)_" onclick="stopParity(this.form,'Read-Check')" disabled></td>
<td id="cancelText"><?if (_var($var,'mdResync')):?>**_(Pause)_** _(will pause Read-Check)_.<?else:?>**_(Resume)_** _(will resume Read-Check)_.<?endif;?><br>**_(Cancel)_** _(will stop Read-Check)_.</td></tr>
<? endif;
$stamps = '/var/tmp/stamps.ini';
$synced = file_exists($stamps) ? explode(',',file_get_contents($stamps)) : [];
$sbSynced = array_shift($synced) ?: _var($var,'sbSynced');
$sbUpdate = _var($var,'mdResyncDt') ? $sbSynced : _var($var,'sbUpdated');?>
<tr><td></td><td><input type="button" value="_(History)_" onclick="parityHistory()"></td>
<td><?=sprintf(_('Current operation %s on **%s**'),(_var($var,'mdResyncDt')?_('started'):_('paused')),_(my_time($sbUpdate).day_count($sbUpdate),0))?></td></tr>
<tr><td>_(Total size)_:</td><td id="line0"></td><td></td></tr>
<tr><td>_(Elapsed time)_:</td><td id="line1"></td><td></td></tr>
<tr><td>_(Current position)_:</td><td id="line2"></td><td></td></tr>
<tr><td>_(Estimated speed)_:</td><td id="line3"></td><td></td></tr>
<tr><td>_(Estimated finish)_:</td><td id="line4"></td><td></td></tr>
<? if ($action[0]=="check"):?>
<? if (count($action)>1):?>
<tr><td><?=_var($var,'mdResyncCorr')==0 ? _('Sync errors detected') : _('Sync errors corrected')?>:</td><td id="line5"></td><td></td></tr>
<? else:?>
<tr><td><?=_var($var,'mdResyncCorr')==0 ? _('Read errors detected') : _('Read errors corrected')?>:</td><td id="line5"></td><td></td></tr>
<? endif;
endif;
endif;
break;
case "Starting":?>
<tr><td><?status_indicator()?>**_(Starting)_...**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td><td></td></tr>
<tr><td></td><td><input type="button" value="_(History)_" onclick="parityHistory()"></td><td></td></tr>
<? break;
case "Formatting":?>
<tr><td><?status_indicator()?>**_(Started, formatting)_...**</td><td><input type="submit" name="cmdStop" value="_(Stop)_" disabled></td><td></td></tr>
<tr><td></td><td><input type="button" value="_(History)_" onclick="parityHistory()"></td><td></td></tr>
<? break;
case "Copying":?>
<tr><td><?status_indicator()?>**_(Starting, copying)_... <span id="fsState"></span>**</td><td><input type="submit" name="cmdNoCopy" value="_(Cancel)_"></td><td></td></tr>
<tr><td></td><td><input type="button" value="_(History)_" onclick="parityHistory()"></td>
<td><?=sprintf(_('Current operation %s on **%s**'),_('started'),_(my_time(_var($var,'sbUpdated',0)).day_count(_var($var,'sbSynced',0)),0))?></td></tr>
<? break;
case "Clearing":?>
<tr><td><?status_indicator()?>**_(Started, clearing)_... <span id="fsState"></span>**</td><td><input type="submit" name="cmdNoClear" value="_(Cancel)_"></td><td></td></tr>
<tr><td></td><td><input type="button" value="_(History)_" onclick="parityHistory()"></td>
<td><?=sprintf(_('Current operation %s on **%s**'),_('started'),_(my_time(_var($var,'sbUpdated',0)).day_count(_var($var,'sbSynced',0)),0))?></td></tr>
<? break;
case "Stopping":?>
<tr><td><?status_indicator()?>**_(Stopping)_...**</td><td><input type="submit" name="cmdStop" value="_(Stop)_" disabled></td><td></td></tr>
<? break;
case "Stopped":
if (_var($var,'configValid')=="error"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Invalid, missing or expired)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="invalid"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Too many attached devices. Please consider upgrading your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="nokeyserver"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Cannot contact key-server. Please check your)_ <a href="/Settings/NetworkSettings">_(network settings)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="withdrawn"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(This Unraid OS release has been withdrawn and may no longer be used. Please)_ <a href="/Plugins">_(update)_</a> _(your server)_.</td></tr>
<? else:
switch (_var($var,'mdState')):
case "STARTED":
?> <tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will bring the array on-line)_.</td></tr>
<? maintenance_mode();
check_encryption();
break;
case "STOPPED":
$action = explode(' ',_var($var,'mdResyncAction'));
if ($action[0]=="recon"):
$resync = resync($action[1]);
?> <tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**<?=_('Start')?>** <?=_("will bring the array on-line and start **$resync**")?>.</td></tr>
<? elseif ($action[0]=="clear"):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(New data disk(s) detected)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will bring the array on-line and start **Disk-Clear** of new data disk(s))_.</td></tr>
<? elseif (_var($var,'sbClean')!="yes" && $action[0]=="check" && count($action)>1):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Unclean shutdown detected)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will bring the array on-line and start **Parity-Check**)_.
<br><input type="checkbox" name="optionCorrect" value="correct" checked><small>_(Write corrections to parity)_</small></td></tr>
<? elseif (_var($var,'sbClean')!="yes" && $action[0]=="check"):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Unclean shutdown detected)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will bring the array on-line)_.</td></tr>
<? elseif (missing_cache()):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Missing Cache disk)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)" disabled></td>
<td>**_(Start)_** _(will remove the missing cache disk and then bring the array on-line)_.
<br><input type="checkbox" name="confirmStart" value="OFF" onclick="$('#cmdStart').prop('disabled',!arrayOps.confirmStart.checked)"><small>_(Yes, I want to do this)_</small></td></tr>
<? else:?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will bring the array on-line)_.</td></tr>
<? endif;
maintenance_mode();
check_encryption();
break;
case "NEW_ARRAY":
if (strpos(_var($disks['parity'],'status'),"DISK_NP")===0 && strpos(_var($disks['parity2'],'status'),"DISK_NP")===0):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will record all disk information and bring the array on-line)_.
<br>_(The array will be immediately available, but **unprotected** since *parity* has not been assigned)_.</td></tr>
<? else:?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Configuration valid)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="parityWarning(this.form,this)"></td>
<td>**_(Start)_** _(will record all disk information, bring the array on-line, and start Parity-Sync)_.
<br>_(The array will be immediately available, but **unprotected** until Parity-Sync completes)_.
<br><input type="checkbox" name="md_invalidslot" value="99">_(Parity is already valid)_.</td></tr>
<? endif;
maintenance_mode();
check_encryption();
break;
case "DISABLE_DISK":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Missing disk)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)" disabled></td>
<td>**_(Start)_** _(will disable the missing disk and then bring the array on-line. Install a replacement disk as soon as possible)_.
<br><input type="checkbox" name="confirmStart" value="OFF" onclick="$('#cmdStart').prop('disabled',!arrayOps.confirmStart.checked)"><small>_(Yes, I want to do this)_</small></td></tr>
<? maintenance_mode();
check_encryption();
break;
case "RECON_DISK":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Replacement disk installed)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will start **Parity-Sync** and/or **Data-Rebuild**)_.</td></tr>
<? maintenance_mode();
check_encryption();
break;
case "SWAP_DSBL":
if (_var($var,'fsCopyPrcnt')=="100"):?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Upgrading disk/swapping parity)_.</td><td><input type="button" id="cmdStart" value="_(Start)_" onclick="prepareInput(this.form,this)"></td>
<td>**_(Start)_** _(will expand the file system of the data disk (if possible); then bring the array on-line and start Data-Rebuild)_.</td></tr>
<? maintenance_mode();
check_encryption();
else:?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Upgrading disk/swapping parity)_.</td><td><input type="submit" name="cmdCopy" value="_(Copy)_" disabled></td>
<td>**_(Copy)_** _(will copy the parity information to the new *parity* disk)_.
<br>_(Once copy completes, the array may be Started, to initiate Data-Rebuild of the disabled disk)_.
<br><input type="checkbox" name="confirmStart" value="OFF" onclick="arrayOps.cmdCopy.disabled=!arrayOps.confirmStart.checked"><small>_(Yes, I want to do this)_</small></td></tr>
<? endif;
break;
case "ERROR:INVALID_EXPANSION":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Invalid expansion)_.</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(You may not add new disk(s) and also remove existing disk(s))_.</td></tr>
<? break;
case "ERROR:NEW_DISK_TOO_SMALL":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Replacement disk is too small)_.</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(The replacement disk must be as big or bigger than the original)_.</td></tr>
<? break;
case "ERROR:PARITY_NOT_BIGGEST":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Disk in parity slot is not biggest)_.</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(If this is a new array, move the largest disk into the *parity* slot)_.
<br>_(If you are adding a new disk or replacing a disabled disk, try Parity-Swap)_.</td></tr>
<? break;
case "ERROR:TOO_MANY_MISSING_DISKS":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(Invalid configuration)_.</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Too many wrong and/or missing disks)_!</td></tr>
<? break;
case "ERROR:NO_DATA_DISKS":?>
<tr><td><?status_indicator()?>**_(Stopped)_**. _(No data disks)_.</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(No array data disks have been assigned)_!</td></tr>
<? break;
endswitch;
endif;
endswitch;?>
<tr><td></td><td class="line" colspan="2"></td></tr>
</table>
</form>
<?if (_var($var,'fsState')!="Stopped"):?>
<?if ($keyfile):?>
<form name="delete_keyfile" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#file" value="unused">
<input type="hidden" name="#include" value="webGui/include/KeyUpload.php">
<table markdown="1" class="array_status noshift">
<tr><td></td><td><input type="submit" name="#apply" value="_(Delete)_" disabled></td><td>**_(Delete)_** _(will delete the encryption keyfile)_.
<br><input type="checkbox" onchange="toggleApply(this.checked)"><small>_(Yes, I want to do this)_</small></td></tr>
<tr><td></td><td class="line" colspan="2"></td></tr>
</table>
</form>
<?endif;?><!-- markdown fix -->
<table markdown="1" class="array_status noshift">
<tr><td></td><td><input type="button" id="spinup-button" onclick="$('[id^=button-]').prop('disabled',true);toggle_state('up')" value="_(Spin Up)_"><input type="button" id="spindown-button" onclick="$('[id^=button-]').prop('disabled',true);toggle_state('down')" value="_(Spin Down)_"></td>
<td>**_(Spin Up)_** _(will immediately spin up all disks)_.<br>**_(Spin Down)_** _(will immediately spin down all disks)_.</td></tr>
<tr><td></td><td><input type="button" value="_(Clear Stats)_" onclick="toggle_state('Clear')"></td><td>**_(Clear Stats)_** _(will immediately clear all disk statistics)_.</td></tr>
<tr><td></td><td class="line" colspan="2"></td></tr>
</table>
<?if (_var($var,'shareUser')=='e' && $pool_devices):?>
<form name="mover_schedule" method="POST" action="/update.htm" target="progressFrame">
<table markdown="1" class="array_status noshift">
<tr><td></td><td><input type="submit" id="mover-button" name="cmdStartMover" value="_(Move)_"></td><td id="mover-text"></td></tr>
</table>
</form>
<?endif;?>
<?elseif ($wrong && $keyfile):?>
<form name="delete_keyfile" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#file" value="unused">
<input type="hidden" name="#include" value="webGui/include/KeyUpload.php">
<table markdown="1" class="array_status noshift">
<tr><td></td><td><input type="submit" name="#apply" value="_(Delete)_"></td><td>**_(Delete)_** _(will delete the encryption keyfile)_.</td></tr>
<tr><td></td><td class="line" colspan="2"></td></tr>
</table>
</form>
<?endif;?><!-- markdown fix -->
<form name="shutdownOps" method="POST" action="/webGui/include/Boot.php">
<table markdown="1" class="array_status noshift">
<tr><td></td><td><input type="button" name="reboot" value="_(Reboot)_" onclick="shutdown_now(this.form,'reboot')"><input type="button" name="shutdown" value="_(Shutdown)_" onclick="shutdown_now(this.form,'shutdown')"></td>
<td>**_(Reboot)_** _(will activate a *clean* system reset)_.<br>**_(Shutdown)_** _(will activate a *clean* system power down)_.<br><input type="checkbox" name="safemode"><small>_(Reboot in safe mode)_</small></td></tr>
<tr><td></td><td class="line" colspan="2"></td></tr>
</table>
</form>
<!-- markdown fix --></p><?if (isset($display['sleep'])) eval('?>'.parse_file($display['sleep']))?>
:array_status_help:
<?if (_var($var,'fsState')=="Stopped"):?>
:array_devices_help:
<?if ($encrypt):?>
<div></div>
:encryption_help:
<?endif;?>
<?endif;?>
+30
View File
@@ -0,0 +1,30 @@
Menu="Main:3"
Title="Boot Device"
Tag="paw"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
<?if (_var($var,'fsState')=="Started"):?>
$('#tab3').bind({click:function() {$('i.toggle').show('slow');}});
<?endif;?>
</script>
<table class="disk_status wide">
<thead><tr><td>_(Device)_</td><td>_(Identification)_</td><td>_(Temp)_.</td><td>_(Reads)_</td><td>_(Writes)_</td><td>_(Errors)_</td><td>_(FS)_</td><td>_(Size)_</td><td>_(Used)_</td><td>_(Free)_</td></tr></thead>
<tbody id="boot_device">
<?if (isset($disks['flash'])) echo "<tr><td colspan='11'>&nbsp;</td></tr>";?>
</tbody>
</table>
:boot_device_help:
+61
View File
@@ -0,0 +1,61 @@
Title="_(Index of)_ $dir"
Tag="navicon"
Markdown="false"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
function cap($dir,$p) {
return mb_substr($dir,$p,1)=='/' ? '/' : '';
}
function truepath($dir) {
$dir = preg_replace('://+:','/',htmlspecialchars_decode($dir));
$bits = array_filter(explode('/',$dir),'mb_strlen');
$path = [];
foreach ($bits as $bit) {
if ($bit=='.') continue;
if ($bit=='..') array_pop($path); else $path[] = $bit;
}
return cap($dir,0).implode('/',$path);
}
$dir = htmlspecialchars(str_replace('\\','\\\\',truepath($dir)));
?>
<style>
.loc{text-align:left!important;padding-left:0!important}
.title span.left{text-transform:none}
</style>
<script>
$(function(){
timers.browse = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
$.get('/webGui/include/Browse.php',{dir:encodeURIComponent("<?=$dir?>"),path:"<?=$path?>"},function(data){
clearTimeout(timers.browse);
var table = $('table.indexer');
var thead = table.find('thead');
var col = $.cookie('col')||1;
var dir = $.cookie('dir')||0;
table.find('tbody,tfoot').remove();
thead.after(data);
table.bind('sortEnd',function(e,t){
var sort = e.target.config.sortList.toString().split(',');
$.cookie('col',sort[0]);
$.cookie('dir',sort[1]);
});
$('div.spinner.fixed').hide('slow');
table.tablesorter({sortList:[[col,dir],[1,0]],sortAppend:[[1,0]],textAttribute:'data'});
});
});
</script>
<table class="indexer tablesorter shift">
<thead><tr><th>_(Type)_</th><th class='sorter-text'>_(Name)_</th><th>_(Size)_</th><th>_(Last Modified)_</th><th style="width:200px">_(Location)_</th></tr></thead>
</table>
<input type="button" value="_(Done)_" onclick="done('Browse')">
+30
View File
@@ -0,0 +1,30 @@
Menu="CPUset:3"
Title="CPU Isolation"
Tag="icon-cpu"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<form name="is">
<input type="hidden" name="names" value="isolcpus">
<table class='tablesorter shift' style='width:auto'>
<thead><tr><th><i class="fa fa-list"></i> _(Isolation)_</th><?create()?></tr></thead>
<tbody id="table-is"><?=$spinner?></tbody>
</table>
<input type="button" value="_(Apply)_" onclick="apply(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()"><span id="wait-is" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> _(Please wait)_...</span>
</form>
<?if (!$safemode):?>
<?else:?>
<div class="notice">_(CPU isolation is prohibited while system is running in SAFE MODE)_!</div>
<?endif;?>
:cpu_isolation_help:
+30
View File
@@ -0,0 +1,30 @@
Menu="CPUset:2"
Title="CPU Pinning Docker"
Tag="icon-cpu"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?if ($dockerd):?>
<form name="ct">
<input type="hidden" name="names" id="names-ct" value="">
<table class='tablesorter shift' style='width:auto'>
<thead><tr><th><i class="fa fa-list"></i> _(Container)_</th><?create()?></tr></thead>
<tbody id="table-ct"><?=$spinner?></tbody>
</table>
<input type="button" value="_(Apply)_" onclick="apply(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()"><span id="wait-ct" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> _(Please wait)_...</span>
</form>
<?else:?>
<div class="notice">_(No CPU pinning available. Docker service must be started)_</div>
<?endif;?>
:cpu_pinning_help:
+4
View File
@@ -0,0 +1,4 @@
Menu="OtherSettings"
Title="CPU Pinning"
Type="xmenu"
Icon="icon-cpu-pinning"
+209
View File
@@ -0,0 +1,209 @@
Menu="CPUset:1"
Title="CPU Pinning VM"
Tag="icon-cpu"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$libvirtd = pgrep('libvirtd')!==false;
$dockerd = pgrep('dockerd')!==false;
$cpus = cpu_list();
$total = count($cpus);
$spinner = "<tr><td colspan='".($total+2)."'><div class='spinner'></div></td></tr>";
$cpuset = implode(';',$cpus);
function create() {
// create the table header. Make multiple rows when CPU cores are many ;)
global $total,$cpus;
$loop = floor(($total-1)/32)+1;
$text = [];
for ($c = 0; $c < $loop; $c++) {
$max = ($c==$loop-1 ? ($total%32?:32) : 32);
for ($n = 0; $n < $max; $n++) {
[$cpu1, $cpu2] = my_preg_split('/[,-]/',$cpus[$c*32+$n]);
if (empty($text[$n])) $text[$n] = '';
$text[$n] .= "$cpu1<br>";
if ($cpu2) $text[$n] .= "$cpu2<br>";
}
}
$label = implode('<br>',array_fill(0,$loop,'CPU:'.($cpu2 ? '<br>HT:':'')));
echo "<th>$label</th>".implode(array_map(function($t){return "<th>$t</th>";},$text));
}
?>
<style>
table.tablesorter tr>th+th{text-align:right;vertical-align:top}
table.tablesorter tr>td+td+td{vertical-align:top}
table.tablesorter tr>th+th+th,table.tablesorter tr>td+td{text-align:center}
table.tablesorter th:first-child,table.tablesorter td:first-child{width:180px;text-align:left}
input.flat{margin:0}
input.lock{margin:0}
</style>
<script>
String.prototype.strip = function(){return this.replace(/ |\(|\)|\[|\]/g,'');}
String.prototype.encode = function(){return this.replace(/\./g,'%2e');}
function apply(form) {
// disable buttons
$(form).find('input[value="_(Apply)_"]').prop('disabled',true);
$(form).find('input[value="_(Reset)_"]').val("_(Done)_").prop('onclick',null).off('click').click(function(){done();});
$('input[value="_(Done)_"]').prop('disabled',true);
var wait = 0;
var id = $(form).prop('name');
var args = {};
args['id'] = id;
args['names'] = form.names.value.encode();
// get the 'checked' cpus
$(form).find('input[type=checkbox]').each(function(){
if ($(this).prop('checked')) args[$(this).prop('name').encode()] = 'on';
});
// show the instant wait message
$('#wait-'+id).show();
// step 1: prepare the update and report back the changes
$.post('/webGui/include/UpdateOne.php',args,function(reply){
if (reply.error) {
swal({type:'error',title:"_(Assignment error)_",text:reply.error,html:true,confirmButtonText:"_(Ok)_"},function(){
$('#wait-'+id).hide();
$(form).find('input[value="_(Done)_"]').val("_(Reset)_").prop('disabled',false).prop('onclick',null).off('click').click(function(){reset($('form[name="'+id+'"]'));});
});
} else if (reply.success) {
var data = reply.success.split(';');
wait = data.length;
for (var i=0; i < data.length; i++) {
var name = data[i];
$('#'+id+'-'+name.strip()).show('slow');
// step 2: apply the changes by updating the vm or container
$.post('/webGui/include/UpdateTwo.php',{id:id,name:encodeURIComponent(name)},function(reply){
if (reply.error) {
// report error and reload table
swal({type:'error',title:"_(Execution error)_",text:reply.error,html:true,confirmButtonText:"_(Ok)_"},function(){
$('#wait-'+id).hide();
$('input[value="_(Done)_"]').prop('disabled',false);
reset($('form[name="'+id+'"]'));
});
} else {
$('#'+id+'-'+reply.success.strip()).hide('slow');
// cleanup when all is done
if (!--wait) {
setTimeout(function(){$('#wait-'+id).hide();},500);
$('input[value="_(Done)_"]').prop('disabled',false);
// isolated cpus, need reboot notice?
if (id == 'is') notice();
}
}
});
}
} else {
$('#wait-'+id).hide();
$('input[value="_(Done)_"]').prop('disabled',false);
if (id == 'is') notice();
}
});
}
function vm() {
// fetch the current vm assignments
$.post('/webGui/include/CPUset.php',{id:'vm',cpus:'<?=$cpuset?>'},function(d){
var data = d.split('\0');
$('#table-vm').html(data[0]);
$('#names-vm').val(data[1]);
buttons(document.vm);
});
}
function thread2containers(n) {
const selector = $('form[name=ct]').find(`[name$=":${n}"]`);
const checkboxes = selector.length;
const checked = selector.filter(':checked').length;
selector.prop('checked', (checkboxes - checked > checked ? true : false)).change();
}
function ct() {
// fetch the current container assignments
$.post('/webGui/include/CPUset.php',{id:'ct',cpus:'<?=$cpuset?>'},function(d){
var data = d.split('\0');
$('#table-ct').html(data[0]);
$('#names-ct').val(data[1]);
buttons(document.ct);
// inject thread to containers toggles
if($('a[onclick^="thread2containers"]').length === 0) {
$('form[name=ct]').find('thead tr th:gt(1)').each((i, elem) => {
elem.innerHTML = elem.innerHTML.replace(/(\d+)/g, '<a href="#" onclick="thread2containers(this.innerText);return false;" title="_(Toggle thread to containers)_">$1</a>');
});
}
});
}
function is() {
// fetch the current isolcpu assignments
$.post('/webGui/include/CPUset.php',{id:'is',cpus:'<?=$cpuset?>'},function(d){
$('#table-is').html(d);
buttons(document.is);
<?if ($safemode):?>
$('#table-is').find('input[type=checkbox]').prop('disabled',true);
<?endif;?>
});
}
function notice() {
// notice to reboot system after changes
var message = "_(CPU Isolation: A reboot is required to apply changes)_";
$.post('/webGui/include/CPUset.php',{id:'cmd'},function(d){
if (d==1) addRebootNotice(message); else removeRebootNotice(message);
});
}
function reset(form) {
// undo changes without a complete refresh of the page
$(form).find('input[value="_(Apply)_"]').prop('disabled',true);
$(form).find('input[value="_(Reset)_"]').val("_(Done)_").prop('onclick',null).off('click').click(function(){done();});
switch ($(form).prop('name')) {
case 'vm': $('#table-vm').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); vm(); break;
case 'ct': $('#table-ct').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); ct(); break;
case 'is': $('#table-is').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); is(); break;
}
}
function buttons(form) {
$(form).find('input[type=checkbox]').each(function(){$(this).on('change',function(){
var total = $(form).find('input[type=checkbox]').length;
var checked = 'input[name^="'+$(this).prop('name').split(':')[0]+':'+'"]:checked';
var cores = $(form).find(checked).length;
// vms must have at least one core selected
if ($(form).prop('name')=='vm') $(form).find(checked).prop('disabled',cores<2);
// isolation may not have all cores selected
if ($(form).prop('name')=='is' && $(this).prop('checked')) $(this).prop('checked',cores<total);
// we need the Apply and Done buttons react on checkbox changes
$(form).find('input[value="_(Apply)_"]').prop('disabled',false);
$(form).find('input[value="_(Done)_"]').val("_(Reset)_").prop('onclick',null).off('click').click(function(){reset(form);});
});});
}
$(function(){
<?if ($libvirtd):?>
vm();
<?endif;?>
<?if ($dockerd):?>
ct();
<?endif;?>
is();
notice();
});
</script>
<?if ($libvirtd):?>
<form name="vm">
<input type="hidden" name="names" id="names-vm" value="">
<table class='tablesorter shift' style='width:auto'>
<thead><tr><th><i class="fa fa-list"></i> _(VM)_</th><?create()?></tr></thead>
<tbody id="table-vm"><?=$spinner?></tbody>
</table>
<input type="button" value="_(Apply)_" onclick="apply(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()"><span id="wait-vm" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> _(Please wait)_...</span>
</form>
<?else:?>
<div class="notice">_(No CPU pinning available. VM service must be started)_</div>
<?endif;?>
:cpu_vms_help:
+128
View File
@@ -0,0 +1,128 @@
Menu="Main:2"
Title="Pool Devices"
Tag="bullseye"
Cond="($pool_devices || $var['fsState']=='Stopped')"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
function makeList($list) {
return implode(',',array_map('escapestring',$list));
}
function sharename($share) {
return basename($share,'.cfg');
}
$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c';
?>
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-{$display['theme']}.css")?>">
<style>
table.divider{margin-top:20px}
</style>
<script>
function validate(poolname) {
var valid = /^[a-z]([a-z0-9_-]*[a-z_-])*$/;
var reserved = [<?=makeList(explode(',',_var($var,'reservedNames')))?>];
var shares = [<?=makeList(array_map('sharename',glob('boot/config/shares/*.cfg',GLOB_NOSORT)))?>];
var pools = [<?=makeList($pools)?>];
if (!poolname.trim()) return false;
if (reserved.includes(poolname)) {
swal({title:"_(Invalid pool name)_",text:"_(Do not use reserved names)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});
return false;
} else if (shares.includes(poolname)) {
swal({title:"_(Invalid pool name)_",text:"_(Do not use user share names)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});
return false;
} else if (pools.includes(poolname)) {
swal({title:"_(Invalid pool name)_",text:"_(Pool name already exists)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});
return false;
} else if (!valid.test(poolname)) {
swal({title:"_(Invalid pool name)_",text:"_(Use only lowercase with no special characters or leading/trailing digits)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
return true;
}
function addPoolPopup() {
var popup = $('#dialogAddPool');
// Load popup with the template info
popup.html($("#templatePopupPool").html());
// Start Dialog section
popup.dialog({
title: "_(Add Pool)_",
resizable: false,
width: 600,
modal: true,
show : {effect:'fade', duration:250},
hide : {effect:'fade', duration:250},
buttons: {
"_(Add)_": function() {
if (validate($(this).find('input[name="poolName"]').val())) {
$(this).find('form').submit();
$(this).dialog('close');
}
},
"_(Cancel)_": function() {
$(this).dialog('close');
}
}
});
$(".ui-dialog .ui-dialog-titlebar").addClass('menu');
$('.ui-dialog .ui-dialog-titlebar-close').css({'display':'none'});
$(".ui-dialog .ui-dialog-title").css({'text-align':'center','width':'100%'});
$(".ui-dialog .ui-dialog-content").css({'padding-top':'15px','vertical-align':'bottom'});
$(".ui-widget-content").css({'background':'<?=$bgcolor?>'});
$(".ui-button-text").css({'padding':'0px 5px'});
}
<?if (_var($var,'fsState')=="Started"):?>
$('#tab2').bind({click:function() {$('i.toggle').show('slow');}});
<?endif;?>
</script>
<?$i = 0?>
<?foreach ($pools as $pool):?>
<?if (isset($disks[$pool]['devices']) or _var($var,'fsState')=="Stopped"):?>
<table class="disk_status wide<?=$i?' divider':''?>">
<thead><tr><td>_(Device)_</td><td>_(Identification)_</td><td>_(Temp)_.</td><td>_(Reads)_</td><td>_(Writes)_</td><td>_(Errors)_</td><td>_(FS)_</td><td>_(Size)_</td><td>_(Used)_</td><td>_(Free)_</td></tr></thead>
<tbody id="pool_device<?=$i++?>">
<?foreach (cache_filter($disks) as $disk) if (prefix($disk['name'])==$pool) echo "<tr><td colspan='11'>&nbsp;</td></tr>"?>
</tbody>
</table>
<?endif;?>
<?endforeach;?>
<?if (_var($var,'fsState')=="Stopped"):?>
<input type="button" value="_(Add Pool)_" style="margin:0" onclick="addPoolPopup()">
<div id="dialogAddPool" style="display:none"></div>
<div id="templatePopupPool" style="display:none">
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="return validate(this.poolName.value)">
<input type="hidden" name="changeSlots" value="apply">
_(Name)_:
: <input type="text" name="poolName" maxlength="40" value="<?=count($pools)==0?'cache':''?>">
_(Slots)_:
: <select name="poolSlots">
<?for ($n=1; $n<=_var($var,'MAX_CACHESZ',0); $n++):?>
<?=mk_option(1,$n,$n)?>
<?endfor;?>
</select>
</form>
</div>
<?endif;?>
:cache_devices_help:
<?if (_var($var,'fsState')=="Stopped"):?>
<div></div>
:cache_slots_help:
<?endif;?>
+48
View File
@@ -0,0 +1,48 @@
Menu="UserPreferences"
Title="Confirmations"
Icon="icon-confirmations"
Tag="check-square"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<form markdown="1" name="confirm_settings" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg"/>
<input type="hidden" name="#section" value="confirm"/>
_(Confirm reboot & powerdown commands)_:
: <select name="down">
<?=mk_option($confirm['down'], "0", _('No'))?>
<?=mk_option($confirm['down'], "1", _('Yes'))?>
</select>
:confirm_reboot_help:
_(Confirm array stop command)_:
: <select name="stop">
<?=mk_option($confirm['stop'], "0", _('No'))?>
<?=mk_option($confirm['stop'], "1", _('Yes'))?>
</select>
:confirm_array_stop_help:
<?if (isset($confirm['sleep'])):?>
_(Confirm sleep command)_:
: <select name="sleep">
<?=mk_option($confirm['sleep'], "0", _('No'))?>
<?=mk_option($confirm['sleep'], "1", _('Yes'))?>
</select>
<?endif;?>
&nbsp;
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
+50
View File
@@ -0,0 +1,50 @@
Menu="About"
Title="Credits"
Icon="icon-credits"
Tag="trophy"
---
**Unraid webGUI** Copyright &copy; 2005-2023, [Lime Technology, Inc.](http://lime-technology.com)
**Dynamix** Copyright &copy; 2012-2023, Bergware International.
**Extended Docker Configuration Page** Copyright &copy; 2014-2021, Guilherme Jardim.
**VM Manager** Copyright &copy; 2015-2021, Eric Schultz, Derek Macias.
**APC UPS Configuration Page** Copyright &copy; 2015, Dan Landon.
**Simple Features** Copyright &copy; 2012, Andrew Hamer-Adams.
**SysDev UI** Copyright &copy; 2020, Justin Nolan
**Community Applications** Copyright &copy; 2015-2023, Andrew Zawadzki
The Software comprising the Unraid webGui, which is all files within this repository **except** for
files listed below, is licensed under GPL version 2.
* The Lime Technology and Unraid logos are property of Lime Technology, Inc.
and may not be used in any other project without written permission from Lime Technology, Inc.
* Settings, Tools and Case icons. Copyright &copy; 2018-2020, [Magnus Engø.](http://www.magnusengo.net/) Used with permission.
**Unraid**&reg; is a registered trademark of [Lime Technology, Inc.](http://lime-technology.com)
This file shall be included in all copies or substantial portions of the Software.
<?
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
$plugins = '/var/log/plugins';
$credits = [];
foreach (glob("$plugins/lang-*.xml", GLOB_NOSORT) as $link) {
$xml_file = @readlink($link);
if ($xml_file === false) continue;
$lang = language('Language', $xml_file);
$local = language('LanguageLocal', $xml_file);
$author = language('Author', $xml_file);
$credits[] = "<li><p><i>$lang ($local)</i> translation by $author</p></li>";
}
if (count($credits)) echo '<br><b>Language Translations</b> Copyright &copy; 2020-2023, <a href="http://lime-technology.com">Lime Technology, Inc.</a><br><ul>'.implode('',$credits).'</ul>';
?>
<br><input type="button" value="_(Done)_" onclick="done()">
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
Menu="Tasks:1"
Type="xmenu"
Tabs="false"
Code="e943"
Lock="true"
Load="30"
@@ -0,0 +1,63 @@
Menu="Dashboard:0"
Cond="version_compare(parse_ini_file('/etc/unraid-version')['version'],'6.11.9','>')"
---
<?PHP
/*
Create a .page file based on this example file and store the file in your plugin directory
Make sure this file has a unique name not used by the GUI or other plugins
This is an example configuration which is used to add custom tiles to the dashboard
Placement of one or more custom tiles is done under column1, column2 or column3
A column can have as many new custom tiles as needed, each custom tile is a <tbody> element
Each tile must have these two properties set:
"_(description)_" - this is the (translated) description shown in the Content Manager window
"_(Tile tile)_" - this is the (translated) title of the tile shown in bold on the screen
The content of the tile can be any text as required by your plugin, this content is placed inside the <td> element
A number of predefined spans are available to make fields of certain widths and maybe used to follow the GUI alignment
These are:
<span class="w18">
<span class="w26">
<span class="w36">
<span class="w44">
<span class="w72">
*/
$pluginname = "myplugin"; // substitute this entry with the name of your plugin
$mytiles[$pluginname]['column1'] =
<<<EOT
<tbody title="_(description)_">
<tr><td>_(Tile title)_</td></tr>
<tr><td>
## content of the tile ##<br>
single field
</td></tr>
</tbody>
EOT;
$mytiles[$pluginname]['column2'] =
<<<EOT
<tbody title="_(description)_">
<tr><td>_(Tile title)_</td></tr>
<tr><td>
## content of the tile ##<br>
<span class="w26" style="background-color:orange">field 1</span>
<span class="w72" style="background-color:lightgreen">field 2</span>
</td></tr>
</tbody>
EOT;
$mytiles[$pluginname]['column3'] =
<<<EOT
<tbody title="_(description)_">
<tr><td>_(Tile title)_</td></tr>
<tr><td>
## content of the tile ##<br>
<span class="w26" style="background-color:orange">field 1</span>
<span class="w36" style="background-color:lightgreen">field 2</span>
<span class="w36" style="background-color:lightblue">field 3<span>
</td></tr>
</tbody>
EOT;
?>
+89
View File
@@ -0,0 +1,89 @@
Menu="OtherSettings"
Title="Date and Time"
Icon="icon-clock"
Tag="clock-o"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?$keys = explode("\n", file_get_contents('webGui/include/timezones.key'));?>
<form markdown="1" name="datetime_settings" method="POST" action="/update.htm" target="progressFrame">
_(Current date and time)_:
: <?=_(my_time(time()),0)?>
_(Time zone)_:
: <select name="timeZone" size="1"><?
foreach ($keys as $key) {
[$timezone, $city] = my_explode('|', $key);
echo mk_option($var['timeZone'], $timezone, $city);
}
?></select>
:timezone_help:
_(Use NTP)_:
: <select name="USE_NTP" size="1" onchange="checkDateTimeSettings(this.form)">
<?=mk_option($var['USE_NTP'], "yes", _('Yes'))?>
<?=mk_option($var['USE_NTP'], "no", _('No'))?>
</select>
:use_ntp_help:
_(NTP server)_ 1:
: <input type="text" name="NTP_SERVER1" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER1'])?>">
:ntp_server1_help:
_(NTP server)_ 2:
: <input type="text" name="NTP_SERVER2" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER2'])?>">
:ntp_server2_help:
_(NTP server)_ 3:
: <input type="text" name="NTP_SERVER3" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER3'])?>">
:ntp_server3_help:
_(NTP server)_ 4:
: <input type="text" name="NTP_SERVER4" maxlength="40" class="narrow" value="<?=htmlspecialchars($var['NTP_SERVER4'])?>">
:ntp_server4_help:
_(New date and time)_:
: <input type="text" name="newDateTime" maxlength="20" class="narrow" value="<?=my_time(time(), "%F %T")?>">
:current_time_help:
&nbsp;
: <input type="submit" name="setDateTime" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<script>
function checkDateTimeSettings() {
form = document.datetime_settings;
if (form.USE_NTP.value=="yes") {
form.newDateTime.disabled=true;
form.NTP_SERVER1.disabled=false;
form.NTP_SERVER2.disabled=false;
form.NTP_SERVER3.disabled=false;
form.NTP_SERVER4.disabled=false;
} else {
form.newDateTime.disabled=false;
form.NTP_SERVER1.disabled=true;
form.NTP_SERVER2.disabled=true;
form.NTP_SERVER3.disabled=true;
form.NTP_SERVER4.disabled=true;
}
}
$(checkDateTimeSettings);
</script>
+2
View File
@@ -0,0 +1,2 @@
Type="xmenu"
Tabs="true"
@@ -0,0 +1,32 @@
Menu="Device New"
Title="Attributes"
Tag="address-card-o"
Cond="strpos(_var($disks[$name],'status'),'_NP')===false"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
$(function() {
$.post("/webGui/include/SmartInfo.php",{cmd:'attributes',port:'<?=$dev?>',name:'<?=$name?>'}, function(data) {
$('#disk_attributes').html(data);
});
});
</script>
<table class='share_status small'>
<thead><td style="width:40px">#</td><td>_(Attribute Name)_</td><td>_(Flag)_</td><td>_(Value)_</td><td>_(Worst)_</td><td>_(Threshold)_</td><td>_(Type)_</td><td>_(Updated)_</td><td>_(Failed)_</td><td style="width:145px">_(Raw Value)_</td></thead>
<tbody id="disk_attributes"><tr><td colspan='10'><div class="spinner"></div></td></tr></tbody>
</table>
<input type="button" value="_(Done)_" onclick="done()">
:smart_attributes_help:
@@ -0,0 +1,30 @@
Menu="Device New"
Title="Capabilities"
Tag="building"
Cond="strpos(_var($disks[$name],'status'),'_NP')===false"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
$(function() {
$.post("/webGui/include/SmartInfo.php",{cmd:'capabilities',port:'<?=$dev?>',name:'<?=$name?>'}, function(data) {
$('#disk_capabilities_div').html(data);
});
});
</script>
<div id="disk_capabilities_div" class='share_status small'>
</div>
<input type="button" value="_(Done)_" onclick="done()">
:smart_capabilities_help:
@@ -0,0 +1,39 @@
Menu="Device New"
Title="Identity"
Tag="user"
Cond="strpos(_var($disks[$name],'status'),'_NP')===false"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
input[type=date]{border:none;margin-left:-2px;padding-left:0;background:transparent;box-shadow:none}
select.noframe{border:none;margin-left:0;padding-left:0;background:transparent;box-shadow:none}
</style>
<script>
function disklog(disk,key,value) {
$.post('/webGui/include/DiskLog.php',{disk:disk,key:key,value:value});
}
$(function() {
$.post("/webGui/include/SmartInfo.php",{cmd:'identify',port:'<?=$dev?>',name:'<?=$name?>'}, function(data) {
$('#disk_identify').html(data);
});
});
</script>
<table class='share_status small'>
<thead><td style="width:33%">_(Title)_</td><td>_(Information)_</td></thead>
<tbody id="disk_identify"><tr><td colspan='2'><div class="spinner"></div></td></tr></tbody>
</table>
<input type="button" value="_(Done)_" onclick="done()">
:smart_identity_help:
File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
Menu="UNRAID-OS"
Title="Diagnostics"
Icon="icon-diagnostics"
Tag="tv"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
?>
<style>
ul,li{margin:0;padding-top:0;padding-bottom:0}
pre.pre{margin:30px 0}
pre>p{margin:0;padding:0}
pre#swaltext{height:600px!important}
@media (max-width:960px){pre#swaltext{height:400px!important}}
@media (max-width:960px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
@media (max-height:768px){pre#swaltext{height:400px!important}}
@media (max-height:768px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
</style>
<script>
var diagnosticsFile = "";
var nchan_diagnostics = new NchanSubscriber('/sub/diagnostics',{subscriber:'websocket'});
nchan_diagnostics.on('message', function(data) {
if (data == '_DONE_') {
nchan_diagnostics.stop();
$('.sweet-alert').hide('fast').removeClass('nchan');
swal.close();
location = diagnosticsFile;
setTimeout(cleanUp,4000);
} else if (data) {
let box = $('pre#swaltext');
box.html(box.html()+'<br>'+data).scrollTop(box[0].scrollHeight);
}
});
function cleanUp() {
if (document.hasFocus()) {
$.post('/webGui/include/Download.php',{cmd:'delete',file:diagnosticsFile});
$("#download").attr("disabled",false);
diagnosticsFile = "";
} else {
setTimeout(cleanUp,2000);
}
}
function zipfile(){
var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0,-1);
return '<?=$zip?>-diagnostics-'+localISOTime.substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
}
function diagnostics(file) {
var anonymize = $('#anonymize').is(':checked') ? '' : '-a';
nchan_diagnostics.start();
$.post('/webGui/include/Download.php',{cmd:'diag',file:file,anonymize:anonymize},function(zip) {
if (zip) {
diagnosticsFile = zip;
swal({title:"_(Downloading)_...",text:"/boot/logs"+zip+"<hr><pre id='swaltext'></pre>",html:true,animation:'none',showConfirmButton:false});
$('.sweet-alert').addClass('nchan');
$('button.confirm').prop('disabled',true);
} else {
nchan_diagnostics.stop();
$("#download").attr("disabled",false);
}
});
}
</script>
:diagnostics_1_plug:
This utility is used for troubleshooting purposes. It will collect all of the system information and configuration files, and package these files in a single ZIP file which can be saved locally.
Subsequently, this file can be included in your correspondence with Limetech or the Unraid forum.
This will help others to quickly get the inside information of your system and provide better support to your problem. The following information
and configuration files are collected:
:end
<pre class="pre" markdown="1">
:diagnostics_2_plug:
+ */config*
<br>copy all *\*.cfg files*, *go* file and the *super.dat* file. These are configuration files.
+ */config/shares*
<br>copy all *\*.cfg* files. These are user share settings files.
+ *Syslog file(s)*
<br>copy the current *syslog* file and any previous existing *syslog* files.
+ *System*
<br>save output of the following commands:
<br>lsscsi, lspci, lsusb, free, lsof, ps, ethtool & ifconfig.
<br>display of iommu groups.
<br>display of command line parameters (e.g. pcie acs override, pci stubbing, etc).
<br>save system variables.
+ *SMART reports*
<br>save a SMART report of each individual disk present in your system.
+ *Docker*
<br>save files *docker.log*, *libvirtd.log*, *libvirt/qemu/\*.log* and *vfio-pci*.
:end
</pre>
:diagnostics_3_plug:
Clicking **Download** will start the collection process and then instruct your browser to save the zip file locally.
*No personal information such as user names, passwords, or any other file contents not specified above is included
by Unraid OS; however, your server name, IP address, and user share names* **will** *be included.*
*Note that 3rd-party plugins **may** or may not store personal information in plugin-specific configuration files and/or output
to the system log.*
*Use* **Anonymize diagnostics** *when publishing the diagnostics file in the public forum. In private communication with Limetech it is recommended to uncheck this setting and capture all information unaltered.*
:end
<input id='download' type="button" value="_(Download)_" onclick="$(this).attr('disabled',true);diagnostics(zipfile())"><input type="button" value="_(Done)_" onclick="done()"><input type="checkbox" id="anonymize" checked>_(Anonymize diagnostics)_
+70
View File
@@ -0,0 +1,70 @@
Type="xmenu"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
function clone_list($disk) {
global $pools;
return strpos($disk['status'],'_NP')===false && ($disk['type']=='Data' || in_array($disk['name'],$pools));
}
if (count($pages)==2) $tabbed = false;
$refs = []; $n = 0;
foreach ($disks as $ref) {
if ($ref['type']!='Data' && !in_array($ref['name'],$pools)) continue;
if ($ref['fsColor']=='grey-off') continue;
$refs[] = $ref['name'];
if ($ref['name']==$name) $i = $n;
$n++;
}
$end = count($refs)-1;
$prev = urlencode($i>0 ? $refs[$i-1] : $refs[$end]);
$next = urlencode($i<$end ? $refs[$i+1] : $refs[0]);
?>
<style>
div.clone1{position:absolute;right:0;margin-top:0}
div.clone2{position:absolute;right:0;margin-top:48px}
<?if ($themes1):?>
span.wrap{display:inline-block;width:128px}
select.clone{min-width:123px;margin-right:0}
<?else:?>
span.wrap{display:inline-block;width:150px}
select.clone{min-width:145px;margin-right:0}
<?endif;?>
input.clone{margin-left:8px;margin-right:0}
span.clone,i.clone{margin-right:4px}
</style>
<script>
function toggleButton(button,id) {
var disabled = true;
switch (id) {
case false:
case true:
disabled = id;
break;
default:
$('select#'+id+' option').each(function(){if ($(this).prop('selected')==true) disabled = false;});
}
$('input#'+button).prop('disabled',disabled);
}
var ctrl = "<span class='ctrl2 status <?=$tabbed?'vhshift':'vshift'?>'><a href='/Shares/Disk?name=<?=$prev?>' title='previous disk share'><button type='button' style='margin-right:4px'><i class='fa fa-chevron-left fa-fw'></i></button></a><a href='/Shares/Disk?name=<?=$next?>' title='next disk share'><button type='button'><i class='fa fa-chevron-right fa-fw'></i></button></a></span>";
$(function() {
<?if ($tabbed):?>
$('.tabs').append(ctrl);
<?else:?>
$('div[class=title]:first').append(ctrl);
<?endif;?>
});
</script>
+47
View File
@@ -0,0 +1,47 @@
Menu="Shares:2"
Title="Disk Shares"
Tag="user-circle-o"
Cond="_var($var,'fsState')!='Stopped' && _var($var,'shareDisk')!='no'"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
table.share_status thead tr td:first-child{width:15%}
table.share_status thead tr td:nth-child(n+3){width:10%}
</style>
<table class="share_status">
<thead><tr><td>_(Name)_</td><td>_(Comment)_</td><td>_(SMB)_</td><td>_(NFS)_</td><td>_(Type)_</td><td>_(Size)_</td><td>_(Free)_</td></tr></thead>
<tbody id="disk_list"></tbody>
</table>
<input id="compute-disks" type="button" value="_(Compute All)_" onclick="$(this).prop('disabled',true);diskList('',-1)">
:disk_list_help:
<script>
function diskList(name,all) {
timers.diskList = setTimeout(function(){$('div.spinner.fixed').show();},500);
$.post('/webGui/include/DiskList.php',{compute:name,path:"<?=rawurlencode($path)?>",all:all},function(data){
clearTimeout(timers.diskList);
$('div.spinner.fixed').hide();
$('#disk_list').html(data);
if (all!=1) $('#compute-disks').prop('disabled',!data||data.indexOf('colspan=')!=-1);
});
}
function computeDisk(name,status) {
status.html("<i class='fa fa-circle-o-notch fa-spin'></i> _(Please wait)_...");
diskList(name,1);
}
$(diskList('',0));
</script>
+252
View File
@@ -0,0 +1,252 @@
Menu="OtherSettings"
Title="Disk Settings"
Icon="icon-disks"
Tag="icon-disk"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
require_once "$docroot/webGui/include/Preselect.php";
$events = explode('|',$var['smEvents'] ?? $numbers);
function displayTemp($temp) {
global $display;
return (is_numeric($temp) && _var($display,'unit')=='F') ? round(9/5*$temp)+32 : $temp;
}
?>
<style>
span.code{display:inline-block;width:186px}
</style>
<script>
function doDispatch(form) {
var fields = {};
<?if (_var($display,'unit')=='F'):?>
form.display_hot.value = Math.round((form.display_hot.value-32)*5/9);
form.display_max.value = Math.round((form.display_max.value-32)*5/9);
<?endif;?>
fields['#cfg'] = "/boot/config/plugins/dynamix/dynamix.cfg";
fields['#cleanup'] = true;
$(form).find('input[name^="display_"]').each(function(){fields[$(this).attr('name')] = $(this).val(); $(this).prop('disabled',true);});
$.post('/webGui/include/Dispatcher.php',fields);
}
function prepareDiskSettings(form) {
var events = [];
for (var i=0; i < <?=count($preselect)?>; i++) {
if (form.elements['at'+i].checked) events.push(form.elements['at'+i].value);
form.elements['at'+i].disabled = true;
}
var custom = form.smCustom.value.trim();
var custom = custom.length ? custom.split(',') : [];
for (var i=0; i < custom.length; i++) events.push(custom[i].trim());
form.smEvents.value = events.join('|');
if (form.smEvents.value == '<?=$numbers?>') form.smEvents.value = '';
if (form.smLevel.value == 1.00) form.smLevel.value = '';
}
function setIndex(form) {
form.smIndex.value = form.smType.selectedIndex;
}
</script>
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="doDispatch(this)">
_(Enable auto start)_:
: <select name="startArray" size="1">
<?=mk_option($var['startArray'], "no", _('No'))?>
<?=mk_option($var['startArray'], "yes", _('Yes'))?>
</select>
:disk_enable_autostart_help:
_(Default spin down delay)_:
: <select name="spindownDelay" size="1">
<?=mk_option($var['spindownDelay'], "0", _('Never'))?>
<?=mk_option($var['spindownDelay'], "15", "15 "._('minutes'))?>
<?=mk_option($var['spindownDelay'], "30", "30 "._('minutes'))?>
<?=mk_option($var['spindownDelay'], "45", "45 "._('minutes'))?>
<?=mk_option($var['spindownDelay'], "1", "1 "._('hour'))?>
<?=mk_option($var['spindownDelay'], "2", "2 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "3", "3 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "4", "4 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "5", "5 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "6", "6 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "7", "7 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "8", "8 "._('hours'))?>
<?=mk_option($var['spindownDelay'], "9", "9 "._('hours'))?>
</select>
:disk_spindown_delay_help:
_(Enable spinup groups)_:
: <select name="spinupGroups" size="1">
<?=mk_option($var['spinupGroups'], "no", _('No'))?>
<?=mk_option($var['spinupGroups'], "yes", _('Yes'))?>
</select>
:disk_spinup_groups_help:
_(Default file system)_:
: <select name="defaultFsType" size="1">
<?=mk_option($var['defaultFsType'], "xfs", _('xfs'));?>
<?=mk_option($var['defaultFsType'], "zfs", _('zfs'));?>
<?=mk_option($var['defaultFsType'], "btrfs", _('btrfs'));?>
<?=mk_option($var['defaultFsType'], "reiserfs", _('reiserfs'));?>
<?=mk_option($var['defaultFsType'], "luks:xfs", _('xfs')." - "._('encrypted'));?>
<?=mk_option($var['defaultFsType'], "luks:zfs", _('zfs')." - "._('encrypted'));?>
<?=mk_option($var['defaultFsType'], "luks:btrfs", _('btrfs')." - "._('encrypted'));?>
<?=mk_option($var['defaultFsType'], "luks:reiserfs", _('reiserfs')." - "._('encrypted'));?>
</select>
:disk_default_file_system_help:
_(Shutdown time-out)_:
: <input type="text" name="shutdownTimeout" maxlength="10" value="<?=$var['shutdownTimeout']?>" class="narrow">
:disk_shutdown_timeout_help:
_(Tunable (poll_attributes))_:
: <input type="text" name="poll_attributes" maxlength="10" value="<?=$var['poll_attributes']?>" class="narrow"><?=_($var['poll_attributes_status'])?>
:disk_tunable_poll_attributes_help:
_(Tunable (enable NCQ))_:
: <select name="queueDepth" size="1">
<?=mk_option($var['queueDepth'], "auto", _('Auto'))?>
<?=mk_option($var['queueDepth'], "1", _('No'))?>
</select>
:disk_tunable_enable_ncq_help:
_(Tunable (nr_requests))_:
: <input type="text" name="nr_requests" maxlength="10" value="<?=$var['nr_requests']?>" class="narrow"><?=_($var['nr_requests_status'])?>
:disk_tunable_nr_requests_help:
_(Tunable (scheduler))_:
: <select name="md_scheduler" size="1">
<?=mk_option($var['md_scheduler'], "auto", _('Auto'))?>
<?=mk_option($var['md_scheduler'], "mq-deadline", _('mq-deadline'))?>
<?=mk_option($var['md_scheduler'], "kyber", _('kyber'))?>
<?=mk_option($var['md_scheduler'], "bfq", _('bfq'))?>
<?=mk_option($var['md_scheduler'], "none", _('none'))?>
</select>
:disk_tunable_scheduler_help:
_(Tunable (md_num_stripes))_:
: <input type="text" name="md_num_stripes" maxlength="10" value="<?=$var['md_num_stripes']?>" class="narrow"><?=_($var['md_num_stripes_status'])?>
:disk_tunable_md_num_stripes_help:
_(Tunable (md_queue_limit))_:
: <input type="text" name="md_queue_limit" maxlength="10" value="<?=$var['md_queue_limit']?>" class="narrow"><?=_($var['md_queue_limit_status'])?>
:disk_tunable_md_queue_limit_help:
_(Tunable (md_sync_limit))_:
: <input type="text" name="md_sync_limit" maxlength="10" value="<?=$var['md_sync_limit']?>" class="narrow"><?=_($var['md_sync_limit_status'])?>
:disk_tunable_md_sync_limit_help:
_(Tunable (md_write_method))_:
: <select name="md_write_method" size="1">
<?=mk_option($var['md_write_method'], "auto", _('Auto'))?>
<?=mk_option($var['md_write_method'], "0", _('read/modify/write'))?>
<?=mk_option($var['md_write_method'], "1", _('reconstruct write'))?>
</select>
:disk_tunable_md_write_method_help:
_(Default warning disk utilization threshold)_ (%):
: <input type="number" min="0" max="100" name="display_warning" class="narrow" value="<?=_var($display,'warning')?>">
:disk_default_warning_utilization_help:
_(Default critical disk utilization threshold)_ (%):
: <input type="number" min="0" max="100" name="display_critical" class="narrow" value="<?=_var($display,'critical')?>">
:disk_default_critical_utilization_help:
_(Default warning disk temperature threshold)_ (&deg;<?=_var($display,'unit','C')?>):
: <input type="number" min="0" max="300" name="display_hot" class="narrow" value="<?=displayTemp(_var($display,'hot'))?>">
:disk_default_warning_temperature_help:
_(Default critical disk temperature threshold)_ (&deg;<?=_var($display,'unit','C')?>):
: <input type="number" min="0" max="300" name="display_max" class="narrow" value="<?=displayTemp(_var($display,'max'))?>">
:disk_default_critical_temperature_help:
&nbsp;
: <input type="submit" name="changeDisk" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<div class="title"><span class="left"><i class="title fa fa-plus-square"></i>_(Global SMART Settings)_</span></div>
<form markdown="1" name="smart_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareDiskSettings(this)">
<input type="hidden" name="#file" value="/boot/config/smart-all.cfg">
<input type="hidden" name="#include" value="webGui/include/update.smart.php">
<input type="hidden" name="#cleanup" value="true">
<input type="hidden" name="#top" value="1">
<input type="hidden" name="smEvents" value="">
<input type="hidden" name="smIndex" value="0">
_(Default SMART notification value)_:
: <select name="smSelect" size="1">
<?=mk_option(_var($var,'smSelect'), "0", _('Raw'))?>
<?=mk_option(_var($var,'smSelect'), "1", _('Normalized'))?>
</select>
:disk_default_smart_notification_help:
_(Default SMART notification tolerance level)_:
: <select name="smLevel" size="1">
<?=mk_option(_var($var,'smLevel'), "1.00", _('Absolute'))?>
<?=mk_option(_var($var,'smLevel'), "1.05", "5%")?>
<?=mk_option(_var($var,'smLevel'), "1.10", "10%")?>
<?=mk_option(_var($var,'smLevel'), "1.15", "15%")?>
<?=mk_option(_var($var,'smLevel'), "1.20", "20%")?>
<?=mk_option(_var($var,'smLevel'), "1.25", "25%")?>
<?=mk_option(_var($var,'smLevel'), "1.50", "50%")?>
</select>
:disk_default_smart_tolerance_help:
_(Default SMART controller type)_:
: <select name="smType" size="1" onchange="setIndex(this.form)">
<?=mk_option(_var($var,'smType'), "", _('Automatic'))?>
<?=mk_option(_var($var,'smType'), "-d ata", "ATA")?>
<?=mk_option(_var($var,'smType'), "-d nvme", "NVMe")?>
<?=mk_option(_var($var,'smType'), "-d sat", "SAT")?>
<?=mk_option(_var($var,'smType'), "-d scsi", "SCSI")?>
<?=mk_option(_var($var,'smType'), "-d 3ware", "3Ware")?>
<?=mk_option(_var($var,'smType'), "-d aacraid", "Adaptec")?>
<?=mk_option(_var($var,'smType'), "-d areca", "Areca")?>
<?=mk_option(_var($var,'smType'), "-d hpt", "HighPoint")?>
<?=mk_option(_var($var,'smType'), "-d cciss", "HP cciss")?>
<?=mk_option(_var($var,'smType'), "-d marvell", "Marvell")?>
<?=mk_option(_var($var,'smType'), "-d megaraid", "MegaRAID")?>
</select>
:disk_default_smart_controller_help:
_(Default SMART attribute notifications)_:
: <input type="text" name="smCustom" value="<?=_var($var,'smCustom')?>" class="narrow">_(Custom attributes (use comma to separate numbers))_
<?for ($x = 0; $x < count($preselect); $x++):?>
&nbsp;
: <input type="checkbox" name="at<?=$x?>" value="<?=_var($preselect[$x],'code')?>"<?=in_array(_var($preselect[$x],'code'),$events)?' checked':''?>><span class="code">_(Attribute)_ = <?=_var($preselect[$x],'code')?></span><?=_var($preselect[$x],'text')?>
<?endfor;?>
:disk_default_smart_attribute_help:
<input type="submit" name="#default" value="_(Default)_">
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
+340
View File
@@ -0,0 +1,340 @@
Menu="UserPreferences"
Title="Display Settings"
Icon="icon-display"
Tag="desktop"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$void = "<img src='/webGui/images/banner.png' id='image' width='330' height='30' onclick='$(&quot;#drop&quot;).click()' style='cursor:pointer' title='_(Click to select PNG file)_'>";
$icon = "<i class='fa fa-trash top' title='_(Restore default image)_' onclick='restore()'></i>";
$plugins = '/var/log/plugins';
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
?>
<style>
span#dropbox{margin-right:20px;}
i.top{position:relative;padding-left:4px;cursor:pointer;}
select.fixed{max-width:166px}
</style>
<script src="<?autov('/webGui/javascript/jquery.filedrop.js')?>"></script>
<script>
var path = '/boot/config/plugins/dynamix';
var filename = '';
function restore() {
// restore original image and activate APPLY button
$('#dropbox').html("<?=$void?>");
$('select[name="banner"]').trigger('change');
filename = 'reset';
}
function upload() {
// save or delete upload when APPLY is pressed
if (filename=='reset') {
$.post("/webGui/include/FileUpload.php",{cmd:'delete',path:path,filename:'banner.png'});
} else if (filename) {
$.post("/webGui/include/FileUpload.php",{cmd:'save',path:path,filename:filename,output:'banner.png'});
}
}
function presetTime(form) {
var system = form.date.selectedIndex==0;
if (system) form.time.selectedIndex = 0;
form.time.disabled = system;
}
function presetBanner(form) {
if (form.banner.selectedIndex == 0) $('.js-bannerSettings').hide(); else $('.js-bannerSettings').show();
}
function presetRefresh(form) {
for (var i=0,item; item=form.refresh.options[i]; i++) item.value *= -1;
}
function presetPassive(index) {
if (index==0) $('#passive').hide(); else $('#passive').show();
}
function updateDirection(lang) {
// var rtl = ['ar_AR','fa_FA'].includes(lang) ? "dir='rtl' " : "";
// RTL display is not giving the desired results, we keep LTR
var rtl = "";
$('input[name="rtl"]').val(rtl);
}
$(function() {
var dropbox = $('#dropbox');
// attach the drag-n-drop feature to the 'dropbox' element
dropbox.filedrop({
maxfiles:1,
maxfilesize:512, // KB
data: {"csrf_token": "<?=$var['csrf_token']?>"},
url:'/webGui/include/FileUpload.php',
beforeEach:function(file) {
if (!file.type.match(/^image\/.*/)) {
swal({title:"_(Warning)_",text:"_(Only PNG images are allowed)_!",type:"warning",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
},
error: function(err, file, i) {
switch (err) {
case 'BrowserNotSupported':
swal({title:"_(Browser error)_",text:"_(Your browser does not support HTML5 file uploads)_!",type:"error",html:true,confirmButtonText:"_(Ok)_"});
break;
case 'TooManyFiles':
swal({title:"_(Too many files)_",text:"_(Please select one file only)_!",html:true,type:"error"});
break;
case 'FileTooLarge':
swal({title:"_(File too large)_",text:"_(Maximum file upload size is 512K)_ (524,288 _(bytes)_)",type:"error",html:true,confirmButtonText:"_(Ok)_"});
break;
}
},
uploadStarted:function(i,file,count) {
var image = $('img', $(dropbox));
var reader = new FileReader();
image.width = 330;
image.height = 30;
reader.onload = function(e){image.attr('src',e.target.result);};
reader.readAsDataURL(file);
},
uploadFinished:function(i,file,response) {
if (response == 'OK 200') {
if (!filename || filename=='reset') $(dropbox).append("<?=$icon?>");
$('select[name="banner"]').trigger('change');
filename = file.name;
} else {
swal({title:"_(Upload error)_",text:response,type:"error",html:true,confirmButtonText:"_(Ok)_"});
}
}
});
// simulate a drop action when manual file selection is done
$('#drop').bind('change', function(e) {
var files = e.target.files;
if ($('#dropbox').triggerHandler({type:'drop',dataTransfer:{files:files}})==false) e.stopImmediatePropagation();
});
presetTime(document.display_settings);
presetBanner(document.display_settings);
});
</script>
:display_settings_help:
<form markdown="1" name="display_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="upload()">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg">
<input type="hidden" name="#section" value="display">
<input type="hidden" name="rtl" value="<?=$display['rtl']?>">
_(Language)_:
: <select name="locale" class="fixed" onchange="updateDirection(this.value)">
<?echo mk_option($display['locale'], "","English");
foreach (glob("$plugins/lang-*.xml",GLOB_NOSORT) as $xml_file) {
$lang = language('Language', $xml_file);
$home = language('LanguageLocal', $xml_file);
$name = language('LanguagePack', $xml_file);
echo mk_option($display['locale'], $name, "$home ($lang)");
}
?></select>
_(Font size)_:
: <select name="font" id='font'>
<?=mk_option($display['font'], "50",_('Very small'))?>
<?=mk_option($display['font'], "56.25",_('Small'))?>
<?=mk_option($display['font'], "",_('Normal'))?>
<?=mk_option($display['font'], "68.75",_('Large'))?>
<?=mk_option($display['font'], "75",_('Very large'))?>
<?=mk_option($display['font'], "80",_('Huge'))?>
</select>
:display_font_size_help:
_(Terminal font size)_:
: <select name="tty" id="tty">
<?=mk_option($display['tty'], "11",_('Very small'))?>
<?=mk_option($display['tty'], "13",_('Small'))?>
<?=mk_option($display['tty'], "15",_('Normal'))?>
<?=mk_option($display['tty'], "17",_('Large'))?>
<?=mk_option($display['tty'], "19",_('Very large'))?>
<?=mk_option($display['tty'], "21",_('Huge'))?>
</select>
:display_tty_size_help:
_(Date format)_:
: <select name="date" onchange="presetTime(this.form)">
<?=mk_option($display['date'], "%c","_(System Setting)_")?>
<?=mk_option($display['date'], "%A, %Y %B %e",_('Day, YYYY Month D'))?>
<?=mk_option($display['date'], "%A, %e %B %Y",_('Day, D Month YYYY'))?>
<?=mk_option($display['date'], "%A, %B %e, %Y",_('Day, Month D, YYYY'))?>
<?=mk_option($display['date'], "%A, %m/%d/%Y",_('Day, MM/DD/YYYY'))?>
<?=mk_option($display['date'], "%A, %d-%m-%Y",_('Day, DD-MM-YYYY'))?>
<?=mk_option($display['date'], "%A, %d.%m.%Y",_('Day, DD.MM.YYYY'))?>
<?=mk_option($display['date'], "%A, %Y-%m-%d",_('Day, YYYY-MM-DD'))?>
</select>
_(Time format)_:
: <select name="time">
<?=mk_option($display['time'], "%I:%M %p",_('12 hours'))?>
<?=mk_option($display['time'], "%R",_('24 hours'))?>
</select>
_(Number format)_:
: <select name="number">
<?=mk_option($display['number'], ".,",_('[D] dot : [G] comma'))?>
<?=mk_option($display['number'], ". ",_('[D] dot : [G] space'))?>
<?=mk_option($display['number'], ".",_('[D] dot : [G] none'))?>
<?=mk_option($display['number'], ",.",_('[D] comma : [G] dot'))?>
<?=mk_option($display['number'], ", ",_('[D] comma : [G] space'))?>
<?=mk_option($display['number'], ",",_('[D] comma : [G] none'))?>
</select>
_(Number scaling)_:
: <select name="scale">
<?=mk_option($display['scale'], "-1",_('Automatic'))?>
<?=mk_option($display['scale'], "0",_('Disabled'))?>
<?=mk_option($display['scale'], "1",_('KB'))?>
<?=mk_option($display['scale'], "2",_('MB'))?>
<?=mk_option($display['scale'], "3",_('GB'))?>
<?=mk_option($display['scale'], "4",_('TB'))?>
<?=mk_option($display['scale'], "5",_('PB'))?>
</select>
_(Page view)_:
: <select name="tabs">
<?=mk_option($display['tabs'], "0",_('Tabbed'))?>
<?=mk_option($display['tabs'], "1",_('Non-tabbed'))?>
</select>
:display_page_view_help:
_(Placement of Users menu)_:
: <select name="users">
<?=mk_option($display['users'], "Tasks:3",_('Header menu'))?>
<?=mk_option($display['users'], "UserPreferences",_('Settings menu'))?>
</select>
:display_users_menu_help:
_(Listing height)_:
: <select name="resize">
<?=mk_option($display['resize'], "0",_('Automatic'))?>
<?=mk_option($display['resize'], "1",_('Fixed'))?>
</select>
:display_listing_height_help:
_(Display device name)_:
: <select name="raw">
<?=mk_option($display['raw'], "",_('Normalized'))?>
<?=mk_option($display['raw'], "1",_('Raw'))?>
</select>
_(Display world-wide-name in device ID)_:
: <select name="wwn">
<?=mk_option($display['wwn'], "0",_('Disabled'))?>
<?=mk_option($display['wwn'], "1",_('Automatic'))?>
</select>
:display_wwn_device_id_help:
_(Display array totals)_:
: <select name="total">
<?=mk_option($display['total'], "0",_('No'))?>
<?=mk_option($display['total'], "1",_('Yes'))?>
</select>
_(Show array utilization indicator)_:
: <select name="usage">
<?=mk_option($display['usage'], "0",_('No'))?>
<?=mk_option($display['usage'], "1",_('Yes'))?>
</select>
_(Temperature unit)_:
: <select name="unit">
<?=mk_option($display['unit'], "C",_('Celsius'))?>
<?=mk_option($display['unit'], "F",_('Fahrenheit'))?>
</select>
:display_temperature_unit_help:
_(Show Dashboard apps)_:
: <select name="dashapps">
<?=mk_option($display['dashapps'], "icons",_('Docker + VMs'))?>
<?=mk_option($display['dashapps'], "docker",_('Docker only'))?>
<?=mk_option($display['dashapps'], "vms",_('VMs only'))?>
<?=mk_option($display['dashapps'], "none",_('None'))?>
</select>
_(Dynamix color theme)_:
: <select name="theme">
<?foreach (glob("$docroot/webGui/styles/dynamix-*.css") as $themes):?>
<?$theme = substr(basename($themes,'.css'),8);?>
<?=mk_option($display['theme'], $theme, _(ucfirst($theme)))?>
<?endforeach;?>
</select>
_(Used / Free columns)_:
: <select name="text">
<?=mk_option($display['text'], "0",_('Text'))?>
<?=mk_option($display['text'], "1",_('Bar (gray)'))?>
<?=mk_option($display['text'], "2",_('Bar (color)'))?>
<?=mk_option($display['text'], "10",_('Text - Bar (gray)'))?>
<?=mk_option($display['text'], "20",_('Text - Bar (color)'))?>
<?=mk_option($display['text'], "11",_('Bar (gray) - Text'))?>
<?=mk_option($display['text'], "21",_('Bar (color) - Text'))?>
</select>
_(Header custom text color)_:
: <input type="text" class="narrow" name="header" value="<?=$display['header']?>" maxlength="6" pattern="([0-9a-fA-F]{3}){1,2}" title="_(HTML color code of 3 or 6 hexadecimal digits)_">
:display_custom_text_color_help:
_(Header custom secondary text color)_:
: <input type="text" class="narrow" name="headermetacolor" value="<?=$display['headermetacolor']?>" maxlength="6" pattern="([0-9a-fA-F]{3}){1,2}" title="_(HTML color code of 3 or 6 hexadecimal digits)_">
_(Header custom background color)_:
: <input type="text" class="narrow" name="background" value="<?=$display['background']?>" maxlength="6" pattern="([0-9a-fA-F]{3}){1,2}" title="_(HTML color code of 3 or 6 hexadecimal digits)_">
:display_custom_background_color_help:
_(Header show description)_:
: <select name="headerdescription">
<?=mk_option($display['headerdescription'], "yes",_('Yes'))?>
<?=mk_option($display['headerdescription'], "no",_('No'))?>
</select>
_(Show banner)_:
: <select name="banner" onchange="presetBanner(this.form)">
<?=mk_option($display['banner'], "",_('No'))?>
<?=mk_option($display['banner'], "image",_('Yes'))?>
</select>
<div class="js-bannerSettings" markdown="1" style="display:none">
_(Custom banner)_:
<input type="hidden" name="#custom" value="">
: <span id="dropbox">
<?if (file_exists($banner)):?>
<img src="<?=autov($banner)?>" width="330" height="30" onclick="$('#drop').click()" style="cursor:pointer" title="_(Click to select PNG file)_"><?=$icon?>
<?else:?>
<?=$void?>
<?endif;?>
</span><em>_(Drag-n-drop a PNG file or click the image at the left)_.</em><input type="file" id="drop" accept="image/*" style="display:none">
:display_custom_banner_help:
</div>
<div class="js-bannerSettings" markdown="1" style="display:none">
_(Show banner background color fade)_:
: <select name="showBannerGradient">
<?=mk_option($display['showBannerGradient'], "no",_('No'))?>
<?=mk_option($display['showBannerGradient'], "yes",_('Yes'))?>
</select>
</div>
<input type="submit" name="#default" value="_(Default)_" onclick="filename='reset'">
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
+861
View File
@@ -0,0 +1,861 @@
Menu="NetworkSettings:100"
Title="_(Interface)_ eth0"
Tag="icon-ethernet"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$members = parse_ini_file('state/network.ini',true);
$build = false;
$template = "$docroot/webGui/EthX.page";
$ini = '/var/local/emhttp/network.ini';
$validIP4 = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}";
$validIP6 = "(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(:|([0-9a-fA-F]{1,4}:)+):(([0-9a-fA-F]{1,4}:)*[0-9a-fA-F]{1,4})?)";
$width = [166,300];
// get available ethernet ports (excluding eth0)
exec("ls --indicator-style=none /sys/class/net|grep -P '^eth[1-9][0-9]*$'",$ports);
function locked($source,$port) {
global $members;
foreach ($members as $member => $value) {
if ($member == $source) continue;
if ($value['BONDING']=='yes' && in_array($port,explode(',',$value['BONDNICS']))) return $value['BONDNAME'].' '.$member;
if ($value['BRIDGING']=='yes' && in_array($port,explode(',',$value['BRNICS']))) return $value['BRNAME'].' '.$member;
}
return false;
}
function vlanID($cfg) {
return array_filter($cfg,function($key){return strpos($key,'VLANID:')===0;},ARRAY_FILTER_USE_KEY);
}
function index($key) {
return filter_var($key,FILTER_SANITIZE_NUMBER_INT);
}
// remove non-existing ethernet ports
foreach (glob("$docroot/webGui/Eth[1-9]*.page",GLOB_NOSORT) as $port) {
if (!in_array(strtolower(basename($port,'.page')), $ports)) {
@unlink($port);
$build = true;
}
}
// add new ethernet ports
foreach ($ports as $ethX) {
$file = "$docroot/webGui/".ucfirst($ethX).".page";
if (!file_exists($file)) {
$X = filter_var($ethX,FILTER_SANITIZE_NUMBER_INT);
file_put_contents($file,str_replace(['parentname:nnn','tabX','bondX','brX','ethX'],['NetworkSettings:'.($X+100),'tab'.($X+1),'bond'.$X,'br'.$X,$ethX],file_get_contents($template)));
$build = true;
}
}
// enable interface only when VMs and Docker are stopped
$service = exec("pgrep libvirt") ? _('VM manager') : '';
$service .= exec("pgrep docker") ? ($service ? ' '._('and').' ' : '')._('Docker service') : '';
// eth0 port status
$no_eth0 = exec("ip link show eth0|grep -Pom1 '(NO-CARRIER|state DOWN)'");
// get VLAN interfaces
$vlan_eth0 = $sort_eth0 = [];
if (isset($eth0)) foreach (vlanID($eth0) as $key => $val) {$vlan_eth0[] = index($key); $sort_eth0[] = (int)$val;}
array_multisort($sort_eth0,$vlan_eth0);
?>
<style>
span.red{color:#E68A00}
span.blue{color:#00529B}
span.green{color:#4F8A10}
span.vshift{margin-top:0!important}
input.gap{margin-right:6px}
input.form{font-size:1rem;padding:5px 10px;margin-left:10px}
div.shade-white{background-color:#ededed;margin-top:10px;padding:8px 0 3px 0}
div.shade-black{background-color:#212121;margin-top:10px;padding:8px 0 3px 0}
div.shade-azure{background-color:#edeaef;margin-top:10px;padding:8px 0 3px 0}
div.shade-gray{background-color:#121510;margin-top:10px;padding:8px 0 3px 0}
select.slim{min-width:47px;margin-left:4px}
input.slim{width:32px;margin-left:8px}
</style>
<script>
<?if ($build):?>
refresh(); // automatically include new ethernet ports
<?endif;?>
Array.prototype.same = function(){return this.sort().filter(function(v,i,o){return i&&v===o[i-1]?v:0;}).length;}
function prepareSettings(form) {
var metrics = [];
var metrics6 = [];
if ($(form).find('input[name="#arg[1]"]').val()=='none') return true;
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val()>0) metrics.push($(this).val());});
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val()>0) metrics6.push($(this).val());});
if (metrics.same() || metrics6.same()) {
swal({title:'Duplicate metrics',text:'List of default gateways contains duplicate metric values',type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
if (form.TYPE.value == 'access') {
$(form).find('input[name^="VLANID:"]').prop('disabled',false).val('');
$(form).find('input[name^="DESCRIPTION:"]').not('input[name$=":0"]').prop('disabled',false).val('');
$(form).find('select[name^="PROTOCOL:"]').not('select[name$=":0"]').prop('disabled',false).val('');
$(form).find('select[name^="USE_DHCP:"]').not('select[name$=":0"]').prop('disabled',false).val('');
$(form).find('select[name^="USE_DHCP6:"]').not('select[name$=":0"]').prop('disabled',false).val('');
$(form).find('input[name^="IPADDR:"]').not('input[name$=":0"]').prop('disabled',false).val('');
$(form).find('input[name^="IPADDR6:"]').not('input[name$=":0"]').prop('disabled',false).val('');
$(form).find('select[name^="NETMASK:"]').not('select[name$=":0"]').prop('disabled',false).val('');
$(form).find('input[name^="NETMASK6:"]').not('input[name$=":0"]').prop('disabled',false).val('');
$(form).find('select[name^="GATEWAY:"]').not('select[name$=":0"]').prop('disabled',false).val('');
$(form).find('input[name^="GATEWAY6:"]').not('input[name$=":0"]').prop('disabled',false).val('');
$(form).find('input[name^="METRIC:"]').not('input[name$=":0"]').prop('disabled',false).val('');
$(form).find('select[name^="PRIVACY6:"]').not('select[name$=":0"]').prop('disabled',false).val('');
} else {
var vlans = [];
$(form).find('input[name^="VLANID:"]').each(function(){vlans.push($(this).val());});
if (vlans.same()) {
swal({title:"_(VLAN assignment mismatch)_",text:"_(List of VLANs contains duplicate VLAN numbers)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
}
var member = '';
for (var i=0,item; item=form.BONDNICS.options[i]; i++) {
if (item.selected) {
if (member.length) member += ',';
member += item.value;
item.selected = false;
}
}
item = form.BONDNICS.options[0];
item.value = member;
item.selected = true;
item.disabled = false;
var member = '';
for (var i=0,item; item=form.BRNICS.options[i]; i++) {
if (item.selected) {
if (member.length) member += ',';
member += item.value;
item.selected = false;
}
}
item = form.BRNICS.options[0];
item.value = form.BONDING.value=='yes' ? form.BONDNAME.value : member;
item.selected = true;
item.disabled = false;
if (member.indexOf(',')>0) form.BRSTP.value = 'yes';
$(form).find('select[name^="PROTOCOL:"]').each(function() {
var protocol = $(this).val() || 'ipv4';
var i = $(this).attr('name').split(':')[1];
if (protocol == 'ipv6') {
$(form).find('input[name="IPADDR:'+i+'"]').prop('disabled',false).val('');
$(form).find('select[name="NETMASK:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="GATEWAY:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="METRIC:'+i+'"]').prop('disabled',false).val('');
if (i==0) $(form).find('input[name^="DNS_SERVER"]').prop('disabled',false).val('');
}
if (protocol == 'ipv4') {
$(form).find('input[name="IPADDR6:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="NETMASK6:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="GATEWAY6:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="METRIC6:'+i+'"]').prop('disabled',false).val('');
$(form).find('select[name="PRIVACY6:'+i+'"]').prop('disabled',false).val('');
if (i==0) $(form).find('input[name^="DNS6_SERVER"]').prop('disabled',false).val('');
}
});
$(form).find('select[name^="USE_DHCP:"]').each(function() {
var i = $(this).attr('name').split(':')[1];
var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4';
var metric = $(form).find('input[name="METRIC:'+i+'"]').val();
if ($(this).prop('disabled')==false && $(this).val()=='yes') {
if (protocol != 'ipv6') {
$(form).find('input[name="IPADDR:'+i+'"]').val('_(Obtaining IPv4 address)_...');
$(form).find('input[name="GATEWAY:'+i+'"]').val(metric!='0'?'_(Obtaining IPv4 gateway)_...':'');
}
} else if (protocol != 'ipv6' && $(this).val()=='yes') {
$(form).find('input[name="IPADDR:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="GATEWAY:'+i+'"]').prop('disabled',false).val('');
}
});
$(form).find('select[name^="USE_DHCP6:"]').each(function() {
var i = $(this).attr('name').split(':')[1];
var protocol = $(form).find('select[name="PROTOCOL:'+i+'"]').val() || 'ipv4';
var metric = $(form).find('input[name="METRIC6:'+i+'"]').val();
if ($(this).prop('disabled')==false && $(this).val()=='yes') {
if (protocol != 'ipv4') {
$(form).find('input[name="IPADDR6:'+i+'"]').val('_(Obtaining IPv6 address)_...');
$(form).find('input[name="GATEWAY6:'+i+'"]').val(metric!='0'?'_(Obtaining IPv6 gateway)_...':'');
}
} else if (protocol != 'ipv4' && $(this).val()=='yes') {
$(form).find('input[name="IPADDR6:'+i+'"]').prop('disabled',false).val('');
$(form).find('input[name="GATEWAY6:'+i+'"]').prop('disabled',false).val('');
}
if ($(this).val()!='yes') $(form).find('input[name="PRIVACY6:'+i+'"]').prop('disabled',false).val('');
});
if (form.DHCP_KEEPRESOLV !== undefined && form.DHCP_KEEPRESOLV.value=='no') {
form.DHCP_KEEPRESOLV.disabled = false;
var protocol = $(form).find('select[name="PROTOCOL:0"]').val() || 'ipv4';
if (protocol != 'ipv6') $(form).find('input[name^="DNS_SERVER"]').val('_(Obtaining DNSv4 server)_...');
}
if (form.DHCP6_KEEPRESOLV !== undefined && form.DHCP6_KEEPRESOLV.value=='no') {
form.DHCP6_KEEPRESOLV.disabled = false;
var protocol = $(form).find('select[name="PROTOCOL:0"]').val() || 'ipv4';
if (protocol != 'ipv4') $(form).find('input[name^="DNS6_SERVER"]').val('_(Obtaining DNSv6 server)_...');
}
setTimeout(refresh,25000);
return true;
}
function selectProtocol(form,port,index) {
if (index == null) {
$(form).find('select[name^="PROTOCOL:"]').each(function() {
var protocol = $(this).val() || 'ipv4';
var i = $(this).attr('name').split(':')[1];
var net4 = $('.'+'ipv4-'+port+'-'+i);
var net6 = $('.'+'ipv6-'+port+'-'+i);
var more4 = $('.'+'more-ipv4-'+port+'-'+i);
var more6 = $('.'+'more-ipv6-'+port+'-'+i);
switch (protocol) {
case 'ipv4': net4.show(); net6.hide(); break;
case 'ipv6': net4.hide(); net6.show(); break;
case 'ipv4+ipv6': net4.show(); net6.show(); break;
}
if ($(form).find('select[name="USE_DHCP:'+i+'"]').val()) more4.show(); else more4.hide();
if ($(form).find('select[name="USE_DHCP6:'+i+'"]').val()) more6.show(); else more6.hide();
checkNetworkSettings(form,i,true);
});
} else {
var protocol = $(form).find('select[name="PROTOCOL:'+index+'"]').val() || 'ipv4';
var net4 = $('.'+'ipv4-'+port+'-'+index);
var net6 = $('.'+'ipv6-'+port+'-'+index);
var more4 = $('.'+'more-ipv4-'+port+'-'+index);
var more6 = $('.'+'more-ipv6-'+port+'-'+index);
switch (protocol) {
case 'ipv4': net4.show(); net6.hide(); break;
case 'ipv6': net4.hide(); net6.show(); break;
case 'ipv4+ipv6': net4.show(); net6.show(); break;
}
if ($(form).find('select[name="USE_DHCP:'+index+'"]').val()) more4.show(); else more4.hide();
if ($(form).find('select[name="USE_DHCP6:'+index+'"]').val()) more6.show(); else more6.hide();
checkNetworkSettings(form,index);
if (index==0) {
checkDNSSettings(form);
checkDNSSettings6(form);
}
}
}
function checkNetworkSettings(form,index,start) {
var disabled4 = $(form).find('select[name="USE_DHCP:'+index+'"]').val()!='no';
var disabled6 = $(form).find('select[name="USE_DHCP6:'+index+'"]').val()!='no';
var protocol = $(form).find('select[name="PROTOCOL:'+index+'"]').val() || 'ipv4';
if (protocol != 'ipv6') {
$(form).find('input[name="IPADDR:'+index+'"]').prop('disabled',disabled4).prop('required',!disabled4);
$(form).find('select[name="NETMASK:'+index+'"]').prop('disabled',disabled4);
$(form).find('input[name="GATEWAY:'+index+'"]').prop('disabled',disabled4);
}
if (protocol != 'ipv4') {
$(form).find('input[name="IPADDR6:'+index+'"]').prop('disabled',disabled6).prop('required',!disabled6);
$(form).find('input[name="NETMASK6:'+index+'"]').prop('disabled',disabled6).prop('required',!disabled6);
$(form).find('input[name="GATEWAY6:'+index+'"]').prop('disabled',disabled6);
var privacy = $(form).find('select[name="PRIVACY6:'+index+'"]');
privacy.prop('disabled',!disabled6);
}
if (index==0) {
if (form.DHCP_KEEPRESOLV !== undefined) {
if (!start) form.DHCP_KEEPRESOLV.value = disabled4 ? 'no' : 'yes';
form.DHCP_KEEPRESOLV.disabled = !disabled4;
checkDNSSettings(form);
}
if (form.DHCP6_KEEPRESOLV !== undefined) {
if (!start) form.DHCP6_KEEPRESOLV.value = disabled6 ? 'no' : 'yes';
form.DHCP6_KEEPRESOLV.disabled = !disabled6;
checkDNSSettings6(form);
}
}
}
function checkDNSSettings(form) {
var disabled = form.DHCP_KEEPRESOLV.value=='no';
var protocol = $(form).find('select[name="PROTOCOL:0"]').val() || 'ipv4';
if (protocol != 'ipv6') {
form.DNS_SERVER1.disabled = disabled;
form.DNS_SERVER1.required = !disabled;
form.DNS_SERVER2.disabled = disabled;
form.DNS_SERVER3.disabled = disabled;
if (!form.DNS_SERVER2.value && disabled) $('#dnsserver2').hide(); else $('#dnsserver2').show();
if (!form.DNS_SERVER3.value && disabled) $('#dnsserver3').hide(); else $('#dnsserver3').show();
}
}
function checkDNSSettings6(form) {
var disabled = form.DHCP6_KEEPRESOLV.value=='no';
var protocol = $(form).find('select[name="PROTOCOL:0"]').val() || 'ipv4';
if (protocol != 'ipv4') {
form.DNS6_SERVER1.disabled = disabled;
form.DNS6_SERVER2.disabled = disabled;
form.DNS6_SERVER3.disabled = disabled;
$('#dns6server1').show();
if (!form.DNS6_SERVER2.value && disabled) $('#dns6server2').hide(); else $('#dns6server2').show();
if (!form.DNS6_SERVER3.value && disabled) $('#dns6server3').hide(); else $('#dns6server3').show();
}
}
function checkBondingSettings(form,ctrl,port) {
var disabled = form.BONDING.value=='no';
var mode = form.BONDING_MODE.value;
if (ctrl>=0) {
var me = ctrl==0 ? null : 'slow';
if (disabled) {
$('#bond-members-'+port).hide(me);
} else {
$('#bond-members-'+port).show(me);
$('#bond-'+port).dropdownchecklist('destroy').dropdownchecklist({emptyText:'None', width:<?=$width[0]?>});
}
if (ctrl==1) checkBridgingSettings(form,1,port);
}
if (mode==1 || mode>4 || disabled) {$('#attention0').hide();} else {$('#attention0').show();}
}
function checkBridgingSettings(form,ctrl,port) {
var me = ctrl==0 ? null : 'slow';
var i = 0;
if (form.BRIDGING.value=='yes' && form.BONDING.value=='no') {
$('#bridge-members-'+port).show(me);
$('#bridge-'+port).dropdownchecklist('destroy').dropdownchecklist({emptyText:'None', width:<?=$width[0]?>});
} else {
$('#bridge-members-'+port).hide(me);
}
}
function checkNetworkAccess(form,port) {
if (form.TYPE.value=='access') {
$('.access-'+port).hide();
$(form).find('input[name^="VLANID:"]').prop('required',false);
} else {
$('.access-'+port).show();
$(form).find('input[name^="VLANID:"]').prop('required',true);
}
}
function addVLAN(port) {
var index = 1;
while ($('#index-'+port+'-'+index).length) index++;
var template = $($('<div/>').loadTemplate($('#network-template-'+port)).html().replace(/INDEX/g,index));
var element = $('[id^="index-'+port+'-"]').last();
$(element).after(template);
$('form[name="'+$(element).parent().attr('name')+'"]').find('select').first().trigger('change');
}
function removeVLAN(element) {
var id = $(element).attr('id').split('-');
$(element).remove();
$('#view-'+id[1]).find('select').first().trigger('change');
}
function disableForm(form) {
$(form).find('input,select').not('input[value="_(Done)_"]').prop('disabled',true);
$(form).find('input[name^="DESCRIPTION"],input[name^="#"]').prop('disabled',false);
}
var stopEvent = false;
function noRun(form) {
var arg1 = $(form).find('input[name="#arg[1]"]');
if (arg1.val()=='') arg1.val('none');
stopEvent = true;
}
function doRun(form) {
if (stopEvent) {stopEvent = false; return;}
var arg1 = $(form).find('input[name="#arg[1]"]');
arg1.val($(form).find('input[name="#section"]').val());
}
function portcheck_eth0() {
$.post('/webGui/include/CheckPort.php',{port:'eth0'},function(text) {
var html = $('#user-notice').html();
if (!html || html.indexOf('eth0')>0) showNotice(text);
setTimeout(portcheck_eth0,10000);
});
}
function portToggle(port,cmd) {
$.post('/webGui/include/PortToggle.php',{port:port,cmd:cmd},function(){refresh();});
}
function viewToggle(eth,vlan) {
var tag = vlan ? '#tag-'+eth+'-'+vlan : '#tag-'+eth;
var view = vlan ? '#view-'+eth+'-'+vlan : '#view-'+eth;
if ($(view).is(':visible')) {
$(tag).removeClass('fa-chevron-up').addClass('fa-chevron-down');
$.cookie(view,'hide',{expires:3650});
} else {
$(tag).removeClass('fa-chevron-down').addClass('fa-chevron-up');
$.removeCookie(view);
}
$(view).toggle('slow');
}
var watchDHCP = new NchanSubscriber('/sub/dhcp',{subscriber:'websocket'});
watchDHCP.on('message', function(data) {
data = data.split(' ');
for (var i=0,row; row=data[i]; i++) {
var id = row.split('_');
var form = $('form[name="'+id[0]+'_settings"]');
var key = id[2].split('=');
switch (id[1]) {
case 'I': form.find('input[name="'+key[0].replace('-','_')+'"]').val(key[1]); break;
case 'S': form.find('select[name="'+key[0].replace('-','_')+'"]').val(key[1]); break;
}
}
});
$(function() {
var ctrl = "<span id='wait_eth0' class='status vshift red-text' style='display:none;font-size:1.2rem;font-style:italic'><i class='fa fa-spinner fa-spin'></i> _(Please wait)_... _(configuring interface)_</span>";
var form = document.eth0_settings;
<?if ($tabbed && !$service):?>
$('#tab1').bind({click:function(){
$('#bond-eth0').dropdownchecklist('destroy').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
$('#bridge-eth0').dropdownchecklist('destroy').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
}});
<?endif;?>
if (!$.cookie('#view-eth0')) {$('#view-eth0').show(); $('#tag-eth0').removeClass('fa-chevron-down').addClass('fa-chevron-up');}
<?foreach ($vlan_eth0 as $i):?>
if (!$.cookie('#view-eth0-<?=$i?>')) {$('#view-eth0-<?=$i?>').show(); $('#tag-eth0-<?=$i?>').removeClass('fa-chevron-down').addClass('fa-chevron-up');}
<?endforeach;?>
$('#bond-eth0').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
$('#bridge-eth0').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
checkBondingSettings(form,0,'eth0');
checkBridgingSettings(form,0,'eth0');
checkNetworkAccess(form,'eth0');
selectProtocol(form,'eth0');
<?if ($service):?>
disableForm(form);
$('#bond-eth0').dropdownchecklist('disable');
$('#bridge-eth0').dropdownchecklist('disable');
var protocol = $(form).find('select[name="PROTOCOL:0"]').val() || 'ipv4';
if (form.DNS_SERVER2.value) $('#dnsserver2').show(); else $('#dnsserver2').hide();
if (form.DNS_SERVER3.value) $('#dnsserver3').show(); else $('#dnsserver3').hide();
if (form.DNS6_SERVER1.value) $('#dns6server1').show(); else $('#dns6server1').hide();
if (form.DNS6_SERVER2.value) $('#dns6server2').show(); else $('#dns6server2').hide();
if (form.DNS6_SERVER3.value) $('#dns6server3').show(); else $('#dns6server3').hide();
<?else:?>
checkDNSSettings(form);
checkDNSSettings6(form);
<?endif;?>
<?if ($tabbed):?>
$('.tabs').append(ctrl.replace('vshift',''));
<?else:?>
$('div.title').eq(0).find('span.left').append(ctrl);
<?endif;?>
portcheck_eth0();
watchDHCP.start();
});
</script>
<form markdown="1" name="eth0_settings" method="POST" action="/update.php" target="progressFrame" onchange="doRun(this)" onsubmit="return prepareSettings(this)">
<input type="hidden" name="#file" value="<?=$ini?>">
<input type="hidden" name="#include" value="/webGui/include/update.ethernet.php">
<input type="hidden" name="#section" value="eth0">
<input type="hidden" name="#command" value="/webGui/scripts/netconfig">
<input type="hidden" name="#arg[1]" value="">
<input type="hidden" name="BONDNAME" value="bond0">
<input type="hidden" name="BONDING_MIIMON" value="100">
<input type="hidden" name="BRNAME" value="br0">
<input type="hidden" name="BRSTP" value="no">
<input type="hidden" name="BRFD" value="0">
_(Interface description)_:
: <span class="status vshift"><i id="tag-eth0" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="viewToggle('eth0')"></i></span>
<input type="text" name="DESCRIPTION:0" maxlength="80" value="<?=htmlspecialchars(_var($eth0,"DESCRIPTION:0"))?>" oninput="noRun(this.form)">
:eth_interface_description_help:
<div markdown="1" id="view-eth0" style="display:none">
_(MAC address)_:
: <?=strtoupper(exec("ip link show eth0|grep -Pom1 'ether \K\S+'"))?>
:eth_mac_address_help:
_(Enable bonding)_:
: <select name="BONDING" onchange="checkBondingSettings(this.form,1,'eth0')">
<?=mk_option(_var($eth0,'BONDING'), "no", _("No"))?>
<?=mk_option(_var($eth0,'BONDING'), "yes", _("Yes"))?>
</select>
:eth_enable_bonding_help:
<div markdown="1" id="bond-members-eth0" style="display:none">
_(Bonding mode)_:
: <select name="BONDING_MODE" onchange="checkBondingSettings(this.form,-1,'eth0')">
<?=mk_option(_var($eth0,'BONDING_MODE'), "0", _("balance-rr")." (0)")?>
<?=mk_option(_var($eth0,'BONDING_MODE'), "1", _("active-backup")." (1)",isset($eth0['BONDING_MODE'])?'':'selected')?>
<?=mk_option(_var($eth0,'BONDING_MODE'), "2", _("balance-xor")." (2)")?>
<?=mk_option(_var($eth0,'BONDING_MODE'), "3", _("broadcast")." (3)")?>
<?=mk_option(_var($eth0,'BONDING_MODE'), "4", _("802.3ad")." (4)")?>
<?=mk_option(_var($eth0,'BONDING_MODE'), "5", _("balance-tlb")." (5)")?>
<?=mk_option(_var($eth0,'BONDING_MODE'), "6", _("balance-alb")." (6)")?>
</select>
<span id="attention0" style="display:none">**_(Attention)_:** _(this mode requires a network switch with proper setup and support)_...</span>
:eth_bonding_mode_help:
_(Bonding members of)_ bond0:
: <select id="bond-eth0" name="BONDNICS" multiple="multiple" style="display:none">
<?=mk_option(_var($eth0,'BONDNICS'),'eth0','eth0','selected disabled')?>
<?foreach ($ports as $port):?>
<?if (!locked('eth0',$port)) echo mk_option_check(_var($eth0,'BONDNICS'),$port,$port)?>
<?endforeach;?>
</select>
:eth_bonding_members_help:
</div>
_(Enable bridging)_:
: <select name="BRIDGING" onchange="checkBridgingSettings(this.form,1,'eth0')">
<?=mk_option(_var($eth0,'BRIDGING'), "no", _("No"))?>
<?=mk_option(_var($eth0,'BRIDGING'), "yes", _("Yes"))?>
</select>
:eth_enable_bridging_help:
<div markdown="1" id="bridge-members-eth0" style="display:none">
_(Bridging members of)_ br0:
: <select id="bridge-eth0" name="BRNICS" multiple="multiple" style="display:none">
<?=mk_option(_var($eth0,'BRNICS'),'eth0','eth0','selected disabled')?>
<?foreach ($ports as $port):?>
<?if (!locked('eth0',$port)) echo mk_option_check(_var($eth0,'BRNICS'),$port,$port)?>
<?endforeach;?>
</select>
:eth_bridging_members_help:
</div>
_(Network protocol)_:
: <select name="PROTOCOL:0" onchange="selectProtocol(this.form,'eth0',0)">
<?=mk_option(_var($eth0,"PROTOCOL:0"), 'ipv4', _('IPv4 only'))?>
<?=mk_option(_var($eth0,"PROTOCOL:0"), 'ipv6', _('IPv6 only'))?>
<?=mk_option(_var($eth0,"PROTOCOL:0"), 'ipv4+ipv6', _('IPv4 + IPv6'))?>
</select>
:eth_network_protocol_help:
<div markdown="1" class="ipv4-eth0-0" style="display:none">
_(IPv4 address assignment)_:
: <select name="USE_DHCP:0" onchange="selectProtocol(this.form,'eth0',0)">
<?=mk_option(_var($eth0,"USE_DHCP:0"), 'yes', _('Automatic'))?>
<?=mk_option(_var($eth0,"USE_DHCP:0"), 'no', _('Static'))?>
</select>
:eth_ipv4_address_assignment_help:
<div markdown="1" class="more-ipv4-eth0-0" style="display:none">
_(IPv4 address)_:
: <input type="text" name="IPADDR:0" maxlength="15" value="<?=_var($eth0,"IPADDR:0")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">/<select name="NETMASK:0" class="slim">
<?=mk_option(_var($eth0,"NETMASK:0"), "255.0.0.0", "8")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.0.0", "16")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.128.0", "17")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.192.0", "18")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.224.0", "19")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.240.0", "20")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.248.0", "21")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.252.0", "22")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.254.0", "23")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.0", "24", $eth0["IPADDR:0"]?"":"selected")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.128", "25")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.192", "26")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.224", "27")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.240", "28")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.248", "29")?>
<?=mk_option(_var($eth0,"NETMASK:0"), "255.255.255.252", "30")?>
</select>
:eth_ipv4_address_help:
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:0" maxlength="15" value="<?=_var($eth0,"GATEWAY:0")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:0" min="0" max="9999" value="<?=_var($eth0,"METRIC:0")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv4_default_gateway_help:
</div>
_(IPv4 DNS server assignment)_:
: <select name="DHCP_KEEPRESOLV" onchange="checkDNSSettings(this.form)">
<?=mk_option(_var($eth0,'DHCP_KEEPRESOLV'), "no", _("Automatic"))?>
<?=mk_option(_var($eth0,'DHCP_KEEPRESOLV'), "yes", _("Static"))?>
</select>
:eth_ipv4_dns_server_assignment_help:
_(IPv4 DNS server)_:
: <input type="text" name="DNS_SERVER1" maxlength="15" value="<?=_var($eth0,'DNS_SERVER1')?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
:eth_ipv4_dns_server_help:
<div markdown="1" id="dnsserver2" style="display:none">
_(IPv4 DNS server)_ 2:
: <input type="text" name="DNS_SERVER2" maxlength="15" value="<?=_var($eth0,'DNS_SERVER2')?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
:eth_ipv4_dns_server2_help:
</div>
<div markdown="1" id="dnsserver3" style="display:none">
_(IPv4 DNS server)_ 3:
: <input type="text" name="DNS_SERVER3" maxlength="15" value="<?=_var($eth0,'DNS_SERVER3')?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
:eth_ipv4_dns_server3_help:
</div>
</div>
<div markdown="1" class="ipv6-eth0-0" style="display:none">
_(IPv6 address assignment)_:
: <select name="USE_DHCP6:0" onchange="selectProtocol(this.form,'eth0',0)">
<?=mk_option(_var($eth0,"USE_DHCP6:0"), 'yes', _('Automatic'))?>
<?=mk_option(_var($eth0,"USE_DHCP6:0"), 'no', _('Static'))?>
</select>
:eth_ipv6_address_assignment_help:
<div markdown="1" class="more-ipv6-eth0-0" style="display:none">
_(IPv6 address)_:
: <input type="text" name="IPADDR6:0" maxlength="39" value="<?=_var($eth0,"IPADDR6:0")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">/<input type="number" name="NETMASK6:0" min="1" max="128" value="<?=_var($eth0,"NETMASK6:0")?>" class="slim">
:eth_ipv6_address_help:
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:0" maxlength="39" value="<?=_var($eth0,"GATEWAY6:0")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:0" min="0" max="9999" value="<?=_var($eth0,"METRIC6:0")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv6_default_gateway_help:
_(IPv6 privacy extensions)_:
: <select name="PRIVACY6:0">
<?=mk_option(_var($eth0,"PRIVACY6:0"), "0", _("Disabled"))?>
<?=mk_option(_var($eth0,"PRIVACY6:0"), "2", _("Enabled"))?>
</select>
:eth_ipv6_privacy_extensions_help:
</div>
<div markdown="1" id="dns6server1" style="display:none">
_(IPv6 DNS server assignment)_:
: <select name="DHCP6_KEEPRESOLV" onchange="checkDNSSettings6(this.form)">
<?=mk_option(_var($eth0,'DHCP6_KEEPRESOLV'), "no", _("Automatic"))?>
<?=mk_option(_var($eth0,'DHCP6_KEEPRESOLV'), "yes", _("Static"))?>
</select>
:eth_ipv6_dns_server_assignment_help:
_(IPv6 DNS server)_:
: <input type="text" name="DNS6_SERVER1" maxlength="39" value="<?=_var($eth0,'DNS6_SERVER1')?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
:eth_ipv6_dns_server_help:
</div>
<div markdown="1" id="dns6server2" style="display:none">
_(IPv6 DNS server)_ 2:
: <input type="text" name="DNS6_SERVER2" maxlength="39" value="<?=_var($eth0,'DNS6_SERVER2')?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
:eth_ipv6_dns_server2_help:
</div>
<div markdown="1" id="dns6server3" style="display:none">
_(IPv6 DNS server)_ 3:
: <input type="text" name="DNS6_SERVER3" maxlength="39" value="<?=_var($eth0,'DNS6_SERVER3')?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
:eth_ipv6_dns_server3_help:
</div>
</div>
_(Desired MTU)_:
: <input type="number" name="MTU" min="68" max="9198" value="<?=_var($eth0,'MTU')?>" class="narrow" placeholder="1500">
:eth_desired_mtu_help:
_(Enable VLANs)_:
: <select name="TYPE" onchange="checkNetworkAccess(this.form,'eth0')">
<?=mk_option(_var($eth0,'TYPE'), 'access', _('No'))?>
<?=mk_option(_var($eth0,'TYPE'), 'trunk', _('Yes'))?>
</select>
:eth_enable_vlans_help:
</div>
<div id='index-eth0-0'></div>
<?foreach ($vlan_eth0 as $i):?>
<div markdown="1" id="index-eth0-<?=$i?>" class="access-eth0 shade-<?=$display['theme']?>" style="display:none">
_(Interface description)_:
: <span class="status vshift"><i id="tag-eth0-<?=$i?>" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="viewToggle('eth0','<?=$i?>')"></i></span>
<input type="text" name="DESCRIPTION:<?=$i?>" maxlength="80" value="<?=htmlspecialchars(_var($eth0,"DESCRIPTION:$i"))?>" oninput="noRun(this.form)">
:eth_interface_description_help:
<div markdown="1" id="view-eth0-<?=$i?>" style="display:none">
_(VLAN number)_:
: <input type="number" name="VLANID:<?=$i?>" min="1" max="4095" value="<?=_var($eth0,"VLANID:$i")?>" class="narrow gap" required>
<?if (!$service):?><input type="button" class="form" value="_(Delete VLAN)_" onclick="removeVLAN($('#index-eth0-<?=$i?>'))"><?endif;?>
:eth_vlan_number_help:
_(Network protocol)_:
: <select name="PROTOCOL:<?=$i?>" onchange="selectProtocol(this.form,'eth0',<?=$i?>)">
<?=mk_option(_var($eth0,"PROTOCOL:$i"), 'ipv4', _('IPv4 only'))?>
<?=mk_option(_var($eth0,"PROTOCOL:$i"), 'ipv6', _('IPv6 only'))?>
<?=mk_option(_var($eth0,"PROTOCOL:$i"), 'ipv4+ipv6', _('IPv4 + IPv6'))?>
</select>
:eth_network_protocol_help:
<div markdown="1" class="ipv4-eth0-<?=$i?>" style="display:none">
_(IPv4 address assignment)_:
: <select name="USE_DHCP:<?=$i?>" onchange="selectProtocol(this.form,'eth0',<?=$i?>)">
<?=mk_option(_var($eth0,"USE_DHCP:$i"), 'yes', _('Automatic'))?>
<?=mk_option(_var($eth0,"USE_DHCP:$i"), 'no', _('Static'))?>
<?if ($i>0):?>
<?=mk_option(_var($eth0,"USE_DHCP:$i"), '', _('None'))?>
<?endif;?>
</select>
:eth_ipv4_address_assignment_help:
<div markdown="1" class="more-ipv4-eth0-<?=$i?>" style="display:none">
_(IPv4 address)_:
: <input type="text" name="IPADDR:<?=$i?>" maxlength="15" value="<?=_var($eth0,"IPADDR:$i")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">/<select name="NETMASK:<?=$i?>" class="slim">
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.0.0.0", "8")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.0.0", "16")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.128.0", "17")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.192.0", "18")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.224.0", "19")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.240.0", "20")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.248.0", "21")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.252.0", "22")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.254.0", "23")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.0", "24", _var($eth0,"IPADDR:$i")?"":"selected")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.128", "25")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.192", "26")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.224", "27")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.240", "28")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.248", "29")?>
<?=mk_option(_var($eth0,"NETMASK:$i"), "255.255.255.252", "30")?>
</select>
:eth_ipv4_address_help:
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:<?=$i?>" maxlength="15" value="<?=_var($eth0,"GATEWAY:$i")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:<?=$i?>" min="0" max="9999" value="<?=_var($eth0,"METRIC:$i")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv4_default_gateway_help:
</div>
</div>
<div markdown="1" class="ipv6-eth0-<?=$i?>" style="display:none">
_(IPv6 address assignment)_:
: <select name="USE_DHCP6:<?=$i?>" onchange="selectProtocol(this.form,'eth0',<?=$i?>)">
<?=mk_option(_var($eth0,"USE_DHCP6:$i"), 'yes', _('Automatic'))?>
<?=mk_option(_var($eth0,"USE_DHCP6:$i"), 'no', _('Static'))?>
<?if ($i>0):?>
<?=mk_option(_var($eth0,"USE_DHCP6:$i"), '', _('None'))?>
<?endif;?>
</select>
:eth_ipv6_address_assignment_help:
<div markdown="1" class="more-ipv6-eth0-<?=$i?>" style="display:none">
_(IPv6 address)_:
: <input type="text" name="IPADDR6:<?=$i?>" maxlength="39" value="<?=_var($eth0,"IPADDR6:$i")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">/<input type="number" name="NETMASK6:<?=$i?>" min="1" max="128" value="<?=_var($eth0,"NETMASK6:$i")?>" class="slim">
:eth_ipv6_address_help:
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:<?=$i?>" maxlength="39" value="<?=_var($eth0,"GATEWAY6:$i")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:<?=$i?>" min="0" max="9999" value="<?=_var($eth0,"METRIC6:$i")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv6_default_gateway_help:
_(IPv6 privacy extensions)_:
: <select name="PRIVACY6:<?=$i?>">
<?=mk_option(_var($eth0,"PRIVACY6:$i"), "0", _("Disabled"))?>
<?=mk_option(_var($eth0,"PRIVACY6:$i"), "2", _("Enabled"))?>
</select>
:eth_ipv6_privacy_extensions_help:
</div>
</div>
</div>
</div>
<?endforeach;?>
&nbsp;
: <input type="submit" value="_(Apply)_" onclick="$('#wait_eth0').show()" disabled><input type="button" value="_(Done)_" onclick="done()">
<?if (!$service):?>
<input type="button" class="access-eth0" value="_(Add VLAN)_" onclick="addVLAN('eth0')" style="display:none">
<?else:?><?=sprintf(_('Stop **%s** to make changes, see'),$service).' (<a href="/Settings">'._('Settings').'</a>)'?><?endif;?>
</form>
<script markdown="1" type="text/html" id="network-template-eth0">
<div markdown="1" id="index-eth0-INDEX" class="access-eth0 shade-<?=$display['theme']?>">
_(Interface description)_:
: <span class="status vshift"><i id="tag-eth0-INDEX" class="fa fa-fw fa-chevron-up" style="cursor:pointer" onclick="viewToggle('eth0','INDEX')"></i></span>
<input type="text" name="DESCRIPTION:INDEX" maxlength="80" value="<?=htmlspecialchars(_var($eth0,"DESCRIPTION:INDEX"))?>" oninput="noRun(this.form)">
<div markdown="1" id="view-eth0-INDEX">
_(VLAN number)_:
: <input type="number" name="VLANID:INDEX" min="1" max="4095" value="<?=_var($eth0,"VLANID:INDEX")?>" class="narrow gap" required>
<input type="button" class="form" value="_(Delete VLAN)_" onclick="removeVLAN($('#index-eth0-INDEX'))">
_(Network protocol)_:
: <select name="PROTOCOL:INDEX" onchange="selectProtocol(this.form,'eth0',INDEX)">
<?=mk_option(_var($eth0,"PROTOCOL:INDEX"), 'ipv4', _('IPv4 only'))?>
<?=mk_option(_var($eth0,"PROTOCOL:INDEX"), 'ipv6', _('IPv6 only'))?>
<?=mk_option(_var($eth0,"PROTOCOL:INDEX"), 'ipv4+ipv6', _('IPv4 + IPv6'))?>
</select>
<div markdown="1" class="ipv4-eth0-INDEX" style="display:none">
_(IPv4 address assignment)_:
: <select name="USE_DHCP:INDEX" onchange="selectProtocol(this.form,'eth0',INDEX)">
<?=mk_option(_var($eth0,"USE_DHCP:INDEX"), 'yes', _('Automatic'))?>
<?=mk_option(_var($eth0,"USE_DHCP:INDEX"), 'no', _('Static'))?>
<?=mk_option(_var($eth0,"USE_DHCP:INDEX"), '', _('None'))?>
</select>
<div markdown="1" class="more-ipv4-eth0-INDEX" style="display:none">
_(IPv4 address)_:
: <input type="text" name="IPADDR:INDEX" maxlength="15" value="<?=_var($eth0,"IPADDR:INDEX")?>" class="narrow" pattern="<?=$validIP4?>" title="=_(IPv4 address A.B.C.D)_">/<select name="NETMASK:INDEX" class="slim">
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.0.0.0", "8")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.0.0", "16")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.128.0", "17")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.192.0", "18")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.224.0", "19")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.240.0", "20")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.248.0", "21")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.252.0", "22")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.254.0", "23")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.0", "24", "selected")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.128", "25")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.192", "26")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.224", "27")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.240", "28")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.248", "29")?>
<?=mk_option(_var($eth0,"NETMASK:INDEX"), "255.255.255.252", "30")?>
</select>
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:INDEX" maxlength="15" value="<?=_var($eth0,"GATEWAY:INDEX")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:INDEX" min="1" max="9999" value="<?=_var($eth0,"METRIC:INDEX")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
</div>
</div>
<div markdown="1" class="ipv6-eth0-INDEX" style="display:none">
_(IPv6 address assignment)_:
: <select name="USE_DHCP6:INDEX" onchange="selectProtocol(this.form,'eth0',INDEX)">
<?=mk_option(_var($eth0,"USE_DHCP6:INDEX"), 'yes', _('Automatic'))?>
<?=mk_option(_var($eth0,"USE_DHCP6:INDEX"), 'no', _('Static'))?>
<?=mk_option(_var($eth0,"USE_DHCP6:INDEX"), '', _('None'))?>
</select>
<div markdown="1" class="more-ipv6-eth0-INDEX" style="display:none">
_(IPv6 address)_:
: <input type="text" name="IPADDR6:INDEX" maxlength="39" value="<?=_var($eth0,"IPADDR6:INDEX")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">/<input type="number" name="NETMASK6:INDEX" min="1" max="128" value="<?=_var($eth0,"NETMASK6:INDEX")?>" class="slim">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:INDEX" maxlength="39" value="<?=_var($eth0,"GATEWAY6:INDEX")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:INDEX" min="1" max="9999" value="<?=_var($eth0,"METRIC6:INDEX")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
_(IPv6 privacy extensions)_:
: <select name="PRIVACY6:INDEX">
<?=mk_option(_var($eth0,'PRIVACY6:INDEX'), "0", _("Disabled"))?>
<?=mk_option(_var($eth0,'PRIVACY6:INDEX'), "2", _("Enabled"))?>
</select>
</div>
</div>
</div>
</div>
</script>
+455
View File
@@ -0,0 +1,455 @@
Menu="parentname:nnn"
Title="_(Interface)_ ethX"
Tag="icon-ethernet"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$locked = locked('ethX','ethX');
// get VLAN interfaces
$vlan_ethX = $sort_ethX = [];
if (!$locked && isset($ethX)) foreach (vlanID($ethX) as $key => $val) {$vlan_ethX[] = index($key); $sort_ethX[] = (int)$val;}
array_multisort($sort_ethX,$vlan_ethX);
$cmd = 'Down';
$more = true;
if (strpos($locked,'bond')===0 || strpos($locked,'br')===0) {
[$master_ethX,$root] = my_explode(' ',$locked);
$reason = _('member of')." $master_ethX ("._('see interface')." $root)";
$class = 'green-text';
} elseif (!exec("ip link show ethX|grep -om1 'UP>'")) {
$reason = _("shutdown")." ("._("inactive").")";
$class = 'blue-text';
$cmd = 'Up';
} elseif (empty($ethX)) {
$reason = _("not configured");
$class = 'red-text';
} else {
$more = false;
$class = '';
}
?>
<script>
function portcheck_ethX() {
$.post('/webGui/include/CheckPort.php',{port:'ethX'},function(text) {
var html = $('#user-notice').html();
if (!html || html.indexOf('ethX')>0) showNotice(text);
setTimeout(portcheck_ethX,10000);
});
}
$(function() {
var ctrl = "<span id='wait_ethX' class='status vshift red-text' style='display:none;font-size:1.2rem;font-style:italic'><i class='fa fa-spinner fa-spin'></i> _(Please wait)_... _(configuring interface)_</span>";
var form = document.ethX_settings;
<?if ($tabbed && !$service):?>
$('#tabX').bind({click:function(){
$('#bond-ethX').dropdownchecklist('destroy').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
$('#bridge-ethX').dropdownchecklist('destroy').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
}});
<?endif;?>
if (!$.cookie('#view-ethX')) {$('#view-ethX').show(); $('#tag-ethX').removeClass('fa-chevron-down').addClass('fa-chevron-up');}
<?foreach ($vlan_ethX as $i):?>
if (!$.cookie('#view-ethX-<?=$i?>')) {$('#view-ethX-<?=$i?>').show(); $('#tag-ethX-<?=$i?>').removeClass('fa-chevron-down').addClass('fa-chevron-up');}
<?endforeach;?>
$('#bond-ethX').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
$('#bridge-ethX').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>});
checkBondingSettings(form,0,'ethX');
checkBridgingSettings(form,0,'ethX');
checkNetworkAccess(form,'ethX');
selectProtocol(form,'ethX');
<?if (!$tabbed):?>
$('div.title').each(function(){
if ($(this).text().indexOf('Interface ethX')==0) $(this).find('span.left').append(ctrl);
});
<?endif;?>
<?if (isset($master_ethX)):?>
$('div.slave-ethX').hide();
disableForm(form);
<?elseif ($service):?>
disableForm(form);
<?endif;?>
<?if ($no_eth0):?>
$('input[name="#shut_ethX"]').prop('disabled',true);
<?endif;?>
setTimeout(portcheck_ethX,Number('ethX'.substr(3))*1000);
});
</script>
<form markdown="1" name="ethX_settings" method="POST" action="/update.php" target="progressFrame" onchange="doRun(this)" onsubmit="return prepareSettings(this)">
<input type="hidden" name="#file" value="<?=$ini?>">
<input type="hidden" name="#include" value="/webGui/include/update.ethernet.php">
<input type="hidden" name="#section" value="ethX">
<input type="hidden" name="#command" value="/webGui/scripts/netconfig">
<input type="hidden" name="#arg[1]" value="">
<input type="hidden" name="BONDNAME" value="bondX">
<input type="hidden" name="BONDING_MIIMON" value="100">
<input type="hidden" name="BRNAME" value="brX">
<input type="hidden" name="BRSTP" value="no">
<input type="hidden" name="BRFD" value="0">
_(Interface description)_:
: <span class="status vshift"><i id="tag-ethX" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="viewToggle('ethX')"></i></span>
<?if (!$more):?>
<input type="text" name="DESCRIPTION:0" maxlength="80" value="<?=htmlspecialchars(_var($ethX,"DESCRIPTION:0"))?>" oninput="noRun(this.form)">
<?else:?>
<span class="<?=$class?>"><?=$reason?></span>
<?endif;?>
:eth_interface_description_help:
<div markdown="1" id="view-ethX" style="display:none">
_(MAC address)_:
: <?=strtoupper(exec("ip link show ethX|grep -Pom1 'ether \K\S+'"))?>
:eth_mac_address_help:
<div markdown="1" class="slave-ethX">
_(Enable bonding)_:
: <select name="BONDING" onchange="checkBondingSettings(this.form,1,'ethX')">
<?=mk_option(_var($ethX,'BONDING'), "no", _("No"))?>
<?=mk_option(_var($ethX,'BONDING'), "yes", _("Yes"))?>
</select>
:eth_enable_bonding_help:
<div markdown="1" id="bond-members-ethX" style="display:none">
_(Bonding mode)_:
: <select name="BONDING_MODE" onchange="checkBondingSettings(this.form,-1,'ethX')">
<?=mk_option(_var($ethX,'BONDING_MODE'), "0", _("balance-rr")." (0)")?>
<?=mk_option(_var($ethX,'BONDING_MODE'), "1", _("active-backup")." (1)",isset($ethX['BONDING_MODE'])?'':'selected')?>
<?=mk_option(_var($ethX,'BONDING_MODE'), "2", _("balance-xor")." (2)")?>
<?=mk_option(_var($ethX,'BONDING_MODE'), "3", _("broadcast")." (3)")?>
<?=mk_option(_var($ethX,'BONDING_MODE'), "4", _("802.3ad")." (4)")?>
<?=mk_option(_var($ethX,'BONDING_MODE'), "5", _("balance-tlb")." (5)")?>
<?=mk_option(_var($ethX,'BONDING_MODE'), "6", _("balance-alb")." (6)")?>
</select>
<span id="attention0" style="display:none">**_(Attention)_:** _(this mode requires a network switch with proper setup and support)_...</span>
:eth_bonding_mode_help:
_(Bonding members of)_ bondX:
: <select id="bond-ethX" name="BONDNICS" multiple="multiple" style="display:none">
<?=mk_option(_var($ethX,'BONDNICS'),'ethX','ethX','selected disabled')?>
<?foreach ($ports as $port):?>
<?if ($port!='ethX' && !locked('ethX',$port)) echo mk_option_check(_var($ethX,'BONDNICS'),$port,$port)?>
<?endforeach;?>
</select>
:eth_bonding_members_help:
</div>
_(Enable bridging)_:
: <select name="BRIDGING" onchange="checkBridgingSettings(this.form,1,'ethX')">
<?=mk_option(_var($ethX,'BRIDGING'), "no", _("No"))?>
<?=mk_option(_var($ethX,'BRIDGING'), "yes", _("Yes"))?>
</select>
:eth_enable_bridging_help:
<div markdown="1" id="bridge-members-ethX" style="display:none">
_(Bridging members of)_ brX:
: <select id="bridge-ethX" name="BRNICS" multiple="multiple" style="display:none">
<?=mk_option(_var($ethX,'BRNICS'),'ethX','ethX','selected disabled')?>
<?foreach ($ports as $port):?>
<?if ($port!='ethX' && !locked('ethX',$port)) echo mk_option_check(_var($ethX,'BRNICS'),$port,$port)?>
<?endforeach;?>
</select>
:eth_bridging_members_help:
</div>
_(Network protocol)_:
: <select name="PROTOCOL:0" onchange="selectProtocol(this.form,'ethX',0)">
<?=mk_option(_var($ethX,"PROTOCOL:0"), 'ipv4', _('IPv4 only'))?>
<?=mk_option(_var($ethX,"PROTOCOL:0"), 'ipv6', _('IPv6 only'))?>
<?=mk_option(_var($ethX,"PROTOCOL:0"), 'ipv4+ipv6', _('IPv4 + IPv6'))?>
</select>
:eth_network_protocol_help:
<div markdown="1" class="ipv4-ethX-0" style="display:none">
_(IPv4 address assignment)_:
: <select name="USE_DHCP:0" onchange="selectProtocol(this.form,'ethX',0)">
<?=mk_option(_var($ethX,"USE_DHCP:0"), 'yes', _('Automatic'))?>
<?=mk_option(_var($ethX,"USE_DHCP:0"), 'no', _('Static'))?>
<?=mk_option(_var($ethX,"USE_DHCP:0"), '', _('None'))?>
</select>
:eth_ipv4_address_assignment_help:
<div markdown="1" class="more-ipv4-ethX-0" style="display:none">
_(IPv4 address)_:
: <input type="text" name="IPADDR:0" maxlength="15" value="<?=_var($ethX,"IPADDR:0")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">/<select name="NETMASK:0" class="slim">
<?=mk_option(_var($ethX,"NETMASK:0"), "255.0.0.0", "8")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.0.0", "16")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.128.0", "17")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.192.0", "18")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.224.0", "19")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.240.0", "20")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.248.0", "21")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.252.0", "22")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.254.0", "23")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.0", "24", _var($ethX,"IPADDR:0")?"":"selected")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.128", "25")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.192", "26")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.224", "27")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.240", "28")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.248", "29")?>
<?=mk_option(_var($ethX,"NETMASK:0"), "255.255.255.252", "30")?>
</select>
:eth_ipv4_address_help:
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:0" maxlength="15" value="<?=_var($ethX,"GATEWAY:0")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:0" min="0" max="9999" value="<?=_var($ethX,"METRIC:0")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv4_default_gateway_help:
</div>
</div>
<div markdown="1" class="ipv6-ethX-0" style="display:none">
_(IPv6 address assignment)_:
: <select name="USE_DHCP6:0" onchange="selectProtocol(this.form,'ethX',0)">
<?=mk_option(_var($ethX,"USE_DHCP6:0"), 'yes', _('Automatic'))?>
<?=mk_option(_var($ethX,"USE_DHCP6:0"), 'no', _('Static'))?>
<?=mk_option(_var($ethX,"USE_DHCP6:0"), '', _('None'))?>
</select>
:eth_ipv6_address_assignment_help:
<div markdown="1" class="more-ipv6-ethX-0" style="display:none">
_(IPv6 address)_:
: <input type="text" name="IPADDR6:0" maxlength="39" value="<?=_var($ethX,"IPADDR6:0")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">/<input type="number" name="NETMASK6:0" min="1" max="128" value="<?=_var($ethX,"NETMASK6:0")?>" class="slim">
:eth_ipv6_address_help:
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:0" maxlength="39" value="<?=_var($ethX,"GATEWAY6:0")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:0" min="0" max="9999" value="<?=_var($ethX,"METRIC6:0")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv6_default_gateway_help:
_(IPv6 privacy extensions)_:
: <select name="PRIVACY6:0">
<?=mk_option(_var($ethX,"PRIVACY6:0"), "0", _("Disabled"))?>
<?=mk_option(_var($ethX,"PRIVACY6:0"), "2", _("Enabled"))?>
</select>
:eth_ipv6_privacy_extensions_help:
</div>
</div>
_(Desired MTU)_:
: <input type="number" name="MTU" min="68" max="9198" value="<?=_var($ethX,'MTU')?>" class="narrow" placeholder="1500">
:eth_desired_mtu_help:
_(Enable VLANs)_:
: <select name="TYPE" onchange="checkNetworkAccess(this.form,'ethX')">
<?=mk_option(_var($ethX,'TYPE'), 'access', _('No'))?>
<?=mk_option(_var($ethX,'TYPE'), 'trunk', _('Yes'))?>
</select>
:eth_enable_vlans_help:
</div>
</div>
<div id='index-ethX-0'></div>
<?foreach ($vlan_ethX as $i):?>
<div markdown="1" id="index-ethX-<?=$i?>" class="access-ethX shade-<?=$display['theme']?>" style="display:none">
_(Interface description)_:
: <span class="status vshift"><i id="tag-ethX-<?=$i?>" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="viewToggle('ethX','<?=$i?>')"></i></span>
<input type="text" name="DESCRIPTION:<?=$i?>" maxlength="80" value="<?=htmlspecialchars(_var($ethX,"DESCRIPTION:$i"))?>" oninput="noRun(this.form)">
:eth_interface_description_help:
<div markdown="1" id="view-ethX-<?=$i?>" style="display:none">
_(VLAN number)_:
: <input type="number" name="VLANID:<?=$i?>" min="1" max="4095" value="<?=_var($ethX,"VLANID:$i")?>" class="narrow gap" required>
<?if (!$service):?><input type="button" class="form" value="_(Delete VLAN)_" onclick="removeVLAN($('#index-ethX-<?=$i?>'))"><?endif;?>
:eth_vlan_number_help:
_(Network protocol)_:
: <select name="PROTOCOL:<?=$i?>" onchange="selectProtocol(this.form,'ethX',<?=$i?>)">
<?=mk_option(_var($ethX,"PROTOCOL:$i"), 'ipv4', _('IPv4 only'))?>
<?=mk_option(_var($ethX,"PROTOCOL:$i"), 'ipv6', _('IPv6 only'))?>
<?=mk_option(_var($ethX,"PROTOCOL:$i"), 'ipv4+ipv6', _('IPv4 + IPv6'))?>
</select>
:eth_network_protocol_help:
<div markdown="1" class="ipv4-ethX-<?=$i?>" style="display:none">
_(IPv4 address assignment)_:
: <select name="USE_DHCP:<?=$i?>" onchange="selectProtocol(this.form,'ethX',<?=$i?>)">
<?=mk_option(_var($ethX,"USE_DHCP:$i"), 'yes', _('Automatic'))?>
<?=mk_option(_var($ethX,"USE_DHCP:$i"), 'no', _('Static'))?>
<?=mk_option(_var($ethX,"USE_DHCP:$i"), '', _('None'))?>
</select>
:eth_ipv4_address_assignment_help:
<div markdown="1" class="more-ipv4-ethX-<?=$i?>" style="display:none">
_(IPv4 address)_:
: <input type="text" name="IPADDR:<?=$i?>" maxlength="15" value="<?=_var($ethX,"IPADDR:$i")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">/<select name="NETMASK:<?=$i?>" class="slim">
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.0.0.0", "8")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.0.0", "16")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.128.0", "17")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.192.0", "18")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.224.0", "19")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.240.0", "20")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.248.0", "21")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.252.0", "22")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.254.0", "23")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.0", "24", isset($ethX["IPADDR:$i"])?"":"selected")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.128", "25")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.192", "26")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.224", "27")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.240", "28")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.248", "29")?>
<?=mk_option(_var($ethX,"NETMASK:$i"), "255.255.255.252", "30")?>
</select>
:eth_ipv4_address_help:
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:<?=$i?>" maxlength="15" value="<?=_var($ethX,"GATEWAY:$i")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:<?=$i?>" min="0" max="9999" value="<?=_var($ethX,"METRIC:$i")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv4_default_gateway_help:
</div>
</div>
<div markdown="1" class="ipv6-ethX-<?=$i?>" style="display:none">
_(IPv6 address assignment)_:
: <select name="USE_DHCP6:<?=$i?>" onchange="selectProtocol(this.form,'ethX',<?=$i?>)">
<?=mk_option(_var($ethX,"USE_DHCP6:$i"), 'yes', _('Automatic'))?>
<?=mk_option(_var($ethX,"USE_DHCP6:$i"), 'no', _('Static'))?>
<?=mk_option(_var($ethX,"USE_DHCP6:$i"), '', _('None'))?>
</select>
:eth_ipv6_address_assignment_help:
<div markdown="1" class="more-ipv6-ethX-<?=$i?>" style="display:none">
_(IPv6 address)_:
: <input type="text" name="IPADDR6:<?=$i?>" maxlength="39" value="<?=_var($ethX,"IPADDR6:$i")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">/<input type="number" name="NETMASK6:<?=$i?>" min="1" max="128" value="<?=_var($ethX,"NETMASK6:$i")?>" class="slim">
:eth_ipv6_address_help:
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:<?=$i?>" maxlength="39" value="<?=_var($ethX,"GATEWAY6:$i")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:<?=$i?>" min="0" max="9999" value="<?=_var($ethX,"METRIC6:$i")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
:eth_ipv6_default_gateway_help:
_(IPv6 privacy extensions)_:
: <select name="PRIVACY6:<?=$i?>">
<?=mk_option(_var($ethX,"PRIVACY6:$i"), "0", _("Disabled"))?>
<?=mk_option(_var($ethX,"PRIVACY6:$i"), "2", _("Enabled"))?>
</select>
:eth_ipv6_privacy_extensions_help:
</div>
</div>
</div>
</div>
<?endforeach;?>
&nbsp;
: <input type="submit" value="_(Apply)_" onclick="$('#wait_<?=$tabbed?'eth0':'ethX'?>').show()" disabled><input type="button" value="_(Done)_" onclick="done()">
<input type="button" name="#shut_ethX" value="<?=_('Port '.$cmd)?>" onclick="portToggle('ethX','<?=$cmd?>')">
<?if (!$service):?>
<input type="button" class="access-ethX" value="_(Add VLAN)_" onclick="addVLAN('ethX')" style="display:none">
<?else:?><?=sprintf(_('Stop **%s** to make changes, see'),$service).' (<a href="/Settings">'._('Settings').'</a>)'?><?endif;?>
</form>
<script markdown="1" type="text/html" id="network-template-ethX">
<div markdown="1" id="index-ethX-INDEX" class="access-ethX shade-<?=$display['theme']?>">
_(Interface description)_:
: <span class="status vshift"><i id="tag-ethX-INDEX" class="fa fa-fw fa-chevron-up" style="cursor:pointer" onclick="viewToggle('ethX','INDEX')"></i></span>
<input type="text" name="DESCRIPTION:INDEX" maxlength="80" value="<?=htmlspecialchars(_var($ethX,"DESCRIPTION:INDEX"))?>" oninput="noRun(this.form)">
<div markdown="1" id="view-ethX-INDEX">
_(VLAN number)_:
: <input type="number" name="VLANID:INDEX" min="1" max="4095" value="<?=_var($ethX,"VLANID:INDEX")?>" class="narrow gap" required>
<input type="button" class="form" value="_(Delete VLAN)_" onclick="removeVLAN($('#index-ethX-INDEX'))">
_(Network protocol)_:
: <select name="PROTOCOL:INDEX" onchange="selectProtocol(this.form,'ethX',INDEX)">
<?=mk_option(_var($ethX,"PROTOCOL:INDEX"), 'ipv4', _('IPv4 only'))?>
<?=mk_option(_var($ethX,"PROTOCOL:INDEX"), 'ipv6', _('IPv6 only'))?>
<?=mk_option(_var($ethX,"PROTOCOL:INDEX"), 'ipv4+ipv6', _('IPv4 + IPv6'))?>
</select>
<div markdown="1" class="ipv4-ethX-INDEX" style="display:none">
_(IPv4 address assignment)_:
: <select name="USE_DHCP:INDEX" onchange="selectProtocol(this.form,'ethX',INDEX)">
<?=mk_option(_var($ethX,"USE_DHCP:INDEX"), 'yes', _('Automatic'))?>
<?=mk_option(_var($ethX,"USE_DHCP:INDEX"), 'no', _('Static'))?>
<?=mk_option(_var($ethX,"USE_DHCP:INDEX"), '', _('None'))?>
</select>
<div markdown="1" class="more-ipv4-ethX-INDEX" style="display:none">
_(IPv4 address)_:
: <input type="text" name="IPADDR:INDEX" maxlength="15" value="<?=_var($ethX,"IPADDR:INDEX")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">/<select name="NETMASK:INDEX" class="slim">
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.0.0.0", "8")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.0.0", "16")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.128.0", "17")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.192.0", "18")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.224.0", "19")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.240.0", "20")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.248.0", "21")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.252.0", "22")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.254.0", "23")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.0", "24", "selected")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.128", "25")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.192", "26")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.224", "27")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.240", "28")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.248", "29")?>
<?=mk_option(_var($ethX,"NETMASK:INDEX"), "255.255.255.252", "30")?>
</select>
_(IPv4 default gateway)_:
: <input type="text" name="GATEWAY:INDEX" maxlength="15" value="<?=_var($ethX,"GATEWAY:INDEX")?>" class="narrow" pattern="<?=$validIP4?>" title="_(IPv4 address A.B.C.D)_">
<input type="text" name="METRIC:INDEX" min="1" max="9999" value="<?=_var($ethX,"METRIC:INDEX")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
</div>
</div>
<div markdown="1" class="ipv6-ethX-INDEX" style="display:none">
_(IPv6 address assignment)_:
: <select name="USE_DHCP6:INDEX" onchange="selectProtocol(this.form,'ethX',INDEX)">
<?=mk_option(_var($ethX,"USE_DHCP6:INDEX"), 'yes', _('Automatic'))?>
<?=mk_option(_var($ethX,"USE_DHCP6:INDEX"), 'no', _('Static'))?>
<?=mk_option(_var($ethX,"USE_DHCP6:INDEX"), '', _('None'))?>
</select>
<div markdown="1" class="more-ipv6-ethX-INDEX" style="display:none">
_(IPv6 address)_:
: <input type="text" name="IPADDR6:INDEX" maxlength="39" value="<?=_var($ethX,"IPADDR6:INDEX")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">/<input type="number" name="NETMASK6:INDEX" min="1" max="128" value="<?=_var($ethX,"NETMASK6:INDEX")?>" class="slim">
_(IPv6 default gateway)_:
: <input type="text" name="GATEWAY6:INDEX" maxlength="39" value="<?=_var($ethX,"GATEWAY6:INDEX")?>" pattern="<?=$validIP6?>" title="_(IPv6 address nnnn:xxxx::yyyy)_">
<input type="text" name="METRIC6:INDEX" min="1" max="9999" value="<?=_var($ethX,"METRIC6:INDEX")?>" class="slim"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred, 0 is no default gateway))_*
_(IPv6 privacy extensions)_:
: <select name="PRIVACY6:INDEX">
<?=mk_option(_var($ethX,'PRIVACY6:INDEX'), "0", _("Disabled"))?>
<?=mk_option(_var($ethX,'PRIVACY6:INDEX'), "2", _("Enabled"))?>
</select>
</div>
</div>
</div>
</div>
</script>
+54
View File
@@ -0,0 +1,54 @@
Menu="NetworkServices:999"
Title="FTP Server"
Icon="icon-ftp"
Tag="globe"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020 Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$ftp_userlist_file = "/boot/config/vsftpd.user_list";
$ftp_userlist = "";
if (file_exists($ftp_userlist_file)) {
$ftp_userlist = str_replace("\n", " ", trim(file_get_contents($ftp_userlist_file)));
if ($ftp_userlist === false) $ftp_userlist = "";
}
$ftp_server = exec("lsof -i:21 -Pln|awk '/\(LISTEN\)/{print $2;exit}'") ? 1 : 0;
?>
<script>
$(function() {
showStatus('21');
});
</script>
<form markdown="1" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#command" value="/webGui/scripts/ftpusers">
_(FTP server)_:
: <select name="#arg[1]">
<?=mk_option($ftp_server, "0", _("Disabled"))?>
<?=mk_option($ftp_server, "1", _("Enabled"))?>
</select>
:ftp_server_help:
_(FTP user(s))_:
: <input type="text" name="#arg[2]" size="40" maxlength="80" value="<?=htmlspecialchars($ftp_userlist)?>">
:ftp_users_help:
&nbsp;
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
:ftp_overview_help:
@@ -0,0 +1,23 @@
Menu="Buttons:4"
Title="Feedback"
Icon="icon-u-chat"
Tag="icon-u-chat"
Code="e93e"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function FeedbackButton() {
openChanges("feedback", "_(Feedback)_", "feedback");
}
</script>
+47
View File
@@ -0,0 +1,47 @@
Type="xmenu"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
function clone_list($disk) {
global $pools;
return strpos($disk['status'],'_NP')===false && ($disk['type']=='Data' || in_array($disk['name'],$pools));
}
?>
<style>
div.clone1{position:absolute;right:0;margin-top:0}
div.clone2{position:absolute;right:0;margin-top:48px}
<?if ($themes1):?>
span.wrap{display:inline-block;width:128px}
select.clone{min-width:123px;margin-right:0}
<?else:?>
span.wrap{display:inline-block;width:150px}
select.clone{min-width:145px;margin-right:0}
<?endif;?>
input.clone{margin-left:8px;margin-right:0}
span.clone,i.clone{margin-right:4px}
</style>
<script>
function toggleButton(button,id) {
var disabled = true;
switch (id) {
case false:
case true:
disabled = id;
break;
default:
$('select#'+id+' option').each(function(){if ($(this).prop('selected')==true) disabled = false;});
}
$('input#'+button).prop('disabled',disabled);
}
</script>
+71
View File
@@ -0,0 +1,71 @@
Menu="Flash"
Title="Flash Device Settings"
Tag="usb"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function cleanUp(zip) {
if (document.hasFocus()) {
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_").prop('disabled',false);
$('div.spinner').hide('slow');
$('#pleaseWait').hide('slow');
$.post('/webGui/include/Download.php',{cmd:'unlink',file:zip});
} else {
setTimeout(function(){cleanUp(zip);},2000);
}
}
function backup() {
$('input[value="_(Flash backup)_"]').val('_(Creating Flash backup)_...').prop('disabled',true);
$('div.spinner').show('slow');
$('#pleaseWait').show('slow');
$.post('/webGui/include/Download.php',{cmd:'backup'},function(zip) {
if (zip) {
location = '/'+zip;
setTimeout(function(){cleanUp(zip);},6000);
} else {
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_");
$('div.spinner').hide('slow');
$('#pleaseWait').hide('slow');
swal({title:"_(Creation error)_",text:"_(Insufficient free disk space available)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
}
});
}
</script>
<div id="pleaseWait" style="display:none;text-align:center;margin-bottom:24px"><span class="red-text strong">_(Please wait)_... _(creating Flash backup zip file (this may take several minutes))_</span></div>
_(Flash Vendor)_:
: <?=$var['flashVendor'];?>
_(Flash Product)_:
: <?=$var['flashProduct'];?>&nbsp;
_(Flash GUID)_:
: <?=$var['flashGUID'];?>&nbsp;
<?if (strstr($var['regTy'], "blacklisted")):?>
&nbsp;
: **_(Blacklisted)_** - <a href="http://lime-technology.com/contact" target="_blank">_(Contact Support)_</a>
<?else:?>
&nbsp;
: [_(Registration Key Manager)_](/Tools/Registration)
<?endif;?>
:flash_backup_help:
&nbsp;
: <input type="button" value="_(Flash backup)_" onclick="backup()"><input type="button" value="_(Done)_" onclick="done()">
@@ -0,0 +1,74 @@
Menu="UNRAID-OS"
Title="Hardware Profile"
Icon="icon-profile"
Tag="wrench"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$var = parse_ini_file('state/var.ini');
$keyfile = trim(base64_encode(@file_get_contents($var['regFILE'])));
?>
<script>
function toggle_hw() {
if ($('#hw_details a').html()=="_(Show Details)_") {
$.getJSON('/webGui/include/HardwareCollect.php',function(hwdata) {
$('#hw_details a').html("_(Hide Details)_");
$('#hw_details pre').text(hwdata.hwxml).slideDown('fast');
});
} else {
$('#hw_details a').html("_(Show Details)_");
$('#hw_details pre').slideUp('fast', function(){$(this).html('');});
}
}
function upload() {
$('input[value="Upload"]').val('_(Uploading)_...').prop('disabled',true);
$('#pleaseWait').show('fast');
$.getJSON('/webGui/include/HardwareCollect.php',function(hwdata) {
$.post('https://keys.lime-technology.com/account/hwprofile/upload',{keyfile:hwdata.keyfile,osversion:hwdata.osversion,hwxml:hwdata.hwxml},function(data) {
$('#pleaseWait').hide().html(data.message).fadeIn('fast');
$('input[value="_(Uploading)_..."]').val('_(Uploaded)_!');
}).fail(function(data) {
var msg = "<p>_(Sorry, an error occurred)_. _(Please try again later)_.</p>";
$('#pleaseWait').hide().html(msg).fadeIn('fast');
$('input[value="_(Uploading)_..."]').val("_(Upload)_").prop('disabled',false);
});
});
}
$(function() {
$.getJSON('https://keys.lime-technology.com/account/hwprofile/status',{keyfile:'<?=$keyfile?>'},function(status) {
if (status.last_submitted) {
var d = new Date(status.last_submitted * 1000);
$('#lastUploaded').html("_(Your hardware profile was last submitted on)_ " + d.toLocaleDateString()).fadeIn('fast');
} else {
$('#lastUploaded').html("_(You haven't sent Limetech your hardware profile yet)_").fadeIn('fast');
}
});
});
</script>
_(This utility is used for troubleshooting purposes)_. _(It will collect all of the system hardware information, remove any serial numbers, and securely upload it to LimeTech)_.
<div id="hw_details">
<pre style="display:none;max-height:300px;overflow-y:auto"></pre>
<a href="#" onclick="toggle_hw();return false;">_(Show Details)_</a>
</div>
*_(No personal information such as user names, passwords, or any other file contents is included in the hardware profile)_.*
<div id="lastUploaded" style="color:grey"></div>
<input type="button" value="_(Upload)_" onclick="upload()"><input type="button" value="_(Done)_" onclick="done()">
<br><div id="pleaseWait" style="display:none;font-weight:bold;color:blue;text-align:center">_(Please wait)_... _(uploading hardware information)_ (_(this may take several minutes)_)</div>
+28
View File
@@ -0,0 +1,28 @@
Menu="Buttons:7"
Title="Help"
Icon="icon-u-help"
Code="e934"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function HelpButton() {
if ($('.nav-item.HelpButton').toggleClass('active').hasClass('active')) {
$('.inline_help').show('slow');
$.cookie('help','help');
} else {
$('.inline_help').hide('slow');
$.removeCookie('help');
}
}
</script>
@@ -0,0 +1,58 @@
Menu="OtherSettings"
Type="xmenu"
Title="Identification"
Icon="icon-home"
Tag="home"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$disabled = $var['fsState']!='Stopped' ? 'disabled' : '';
$name_regex = '^[A-Za-z0-9]([A-Za-z0-9\-\.]{0,13}[A-Za-z0-9])?$';
$name_warn = preg_match('/'.$name_regex.'/', $var['NAME']) ? 'none' : 'block';
?>
<form markdown="1" name="NameSettings" method="POST" action="/update.htm" target="progressFrame">
<input type="hidden" name="server_https" value="<?=_var($_SERVER,'HTTPS')?>">
<input type="hidden" name="server_name" value="<?=_var($_SERVER,'HTTP_HOST')?>">
<input type="hidden" name="server_addr" value="<?=_var($_SERVER,'SERVER_ADDR')?>">
_(Server name)_:
: <input type="text" name="NAME" id="NAME" maxlength="15" pattern="<?=$name_regex?>" value="<?=htmlspecialchars(_var($var,'NAME'))?>" title="_(Only alphanumeric characters)_ (&quot;A-Z&quot;, &quot;a-z&quot;, and &quot;0-9&quot;), dashes (&quot;-&quot;), and dots (&quot;.&quot;); _(and, the first and last characters must be alphanumeric)_" <?=$disabled?> required> <span id="name_warning" style="display:<?=$name_warn?>"><i class="fa fa-warning icon warning"></i> _(Not compatible with NetBIOS)_</span>
:id_server_name_help:
_(Description)_:
: <input type="text" name="COMMENT" value="<?=htmlspecialchars(_var($var,'COMMENT'))?>" <?=$disabled?>>
:id_description_help:
_(Model)_:
: <input type="text" name="SYS_MODEL" value="<?=htmlspecialchars(_var($var,'SYS_MODEL'))?>" <?=$disabled?>>
:id_model_help:
&nbsp;
: <input type="submit" name="changeNames" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()"><?if ($disabled):?>*_(Array must be **Stopped** to change)_*<?endif;?>
</form>
<script>
$("#NAME").keypress(function(event) {
return event.key.match(/[A-Za-z0-9\-\.]/)!==null;
});
$("#NAME").on("input change", function() {
if ($(this).val().match(/<?=$name_regex;?>/) === null) {
$('#name_warning').fadeIn('fast');
} else {
$('#name_warning').fadeOut('fast');
}
});
</script>
+22
View File
@@ -0,0 +1,22 @@
Menu="Buttons:5"
Title="Info"
Icon="icon-u-display"
Code="e930"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function InfoButton() {
openChanges("system_information", "_(System Information)_", "sysinfo");
}
</script>
+34
View File
@@ -0,0 +1,34 @@
Menu="Registration"
Title="Install Key"
Tag="flag"
Cond="($var['regTy']!='Pro')"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
span.info{margin-left:12px}
</style>
<script>
function installKey(file) {
file = file.trim();
if (file) openPlugin('install_key '+encodeURIComponent(file), "_(Install Key)_");
}
</script>
<form markdown="1">
<span class="info">_(To install a registration key, paste the key file URL in the box below and click **Install Key**)_.</span>
_(Key file URL)_:
: <input type="text" name="file" id="key_file" maxlength="1024" value="" style="width:33%">
<input type="button" value="_(Install Key)_" onclick="installKey(this.form.file.value.trim())">
</form>
+340
View File
@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
+132
View File
@@ -0,0 +1,132 @@
Menu="WebGui"
Title="Language"
Icon="icon-language"
Tag="icon-language"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
$installed = ['English'];
$plugins = '/var/log/plugins';
$keys = parse_ini_file('webGui/include/languages.key',false,INI_SCANNER_RAW);
$head = '<i class="fa fa-fw fa-trash" title="_(Remove the installed language)_" style="cursor:pointer" onclick="remove(&quot;';
$tail = '&quot;)"></i>';
foreach (glob("$plugins/lang-*.xml",GLOB_NOSORT) as $xml_file) $installed[] = language('LanguageLocal',$xml_file).$head.str_replace('lang-','',basename($xml_file,'.xml')).$tail;
?>
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
<style>
select.wide{min-width:<?=$themes2?'314':'300'?>px}
div.notice{margin-top:70px;margin-bottom:30px}
div#selectlang{margin-top:20px}
label.button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:1.8px;text-transform:uppercase;min-width:86px;margin:0;padding:8px;text-align:center;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:none;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
label.button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
</style>
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
<script>
function execute(cmd,title,language,name,filedata) {
var keys = {};
<?foreach ($keys as $key => $name) echo "keys['$key'] = '".strtok($keys[$key],' (')."'\n";?>
$.post("/webGui/include/FileUpload.php",{cmd:cmd,filename:language,name:encodeURIComponent(name),filedata:filedata},function(list){
if (list.indexOf('Error 500')==-1) {
var installed = [];
if (list.length) {
var name = list.split(',');
for (var i=0; i < name.length; i++) installed.push(keys[name[i]]+(name[i]!='en_US'? '<?=$head?>'+name[i]+'<?=$tail?>' : ''));
}
$('.installed').html(installed.join(', '));
swal({title:title,text:"_(See)_ <a href='/Settings/DisplaySettings'>_(Display Settings)_</a> _(to select your language)_",type:'success',html:true,confirmButtonText:"_(Ok)_"});
$('#uploadbutton').prop('disabled',true);
}
});
}
function remove(language) {
execute('rm', "_(Language support deleted)_", language, '', '');
}
function upload(form) {
var language = form.language;
if (!language.value) {
swal({title:"_(Missing Language)_",text:"_(Please select a language before proceeding)_!",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return;
}
execute('add', "_(Language support added)_", language.value, language.options[language.selectedIndex].text, form.file.value);
}
function getZIPfile(event,form) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var name = input.files[0].name;
if (name.slice(-4)=='.zip') {
form.file.value = reader.result;
$('#uploadbutton').prop('disabled',false);
for (var n = 0; n < form.language.length; n++) if (form.language.options[n].text.indexOf(name.slice(0,-4))>0) {form.language.selectedIndex = n; break;}
} else {
swal({title:"_(Wrong File Extension)_",text:"_(Only ZIP files are allowed)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
}
};
reader.readAsDataURL(input.files[0]);
}
function installXML(name) {
var file = name.trim();
if (file) openPlugin('language install '+file, "_(Install Language)_");
}
$(function() {
$('input.view').switchButton({labels_placement:'left', off_label:"_(User)_", on_label:"_(Developer)_"});
$('input.view').change(function(){$('.user,.developer').toggle('slow');});
});
</script>
<span class="status vhshift"><input type="checkbox" class="view"></span>
<div markdown="1" class="user">
<div class="notice">_(Use this to install official language packs)_</div>
_(Installed languages)_:
: <span class="installed"><?=implode(', ',$installed)?></span>
_(Enter URL of language pack XML file)_
: &nbsp;
<dl>
<form name="xml_install" method="POST" target="progressFrame">
<dt><input type="text" name="file" id="xml_file" maxlength="1024" value="" style="width:90%"></dt>
<dd><input type="button" value="_(Install)_" onclick="installXML(this.form.file.value)" style="margin:0"></dd>
</form>
</dl>
</div>
<div markdown="1" class="developer" style="display:none">
<div class="notice">_(Use this to develop language packs)_</div>
<form markdown="1">
<input type="hidden" name="file" value="">
_(Installed languages)_:
: <span class="installed"><?=implode(', ',$installed)?></span>
_(Select language)_:
: <select name="language" class="wide">
<?=mk_option(1, "", "---")?>
<?foreach ($keys as $key => $name) echo mk_option(1, $key, $name)?>
</select>
<div id="selectlang" markdown="1">
_(Select language file)_:
: <span><label for="files" class="button">_(Browse)_</label><input id="files" type="file" style="display:none" accept=".zip" onchange="getZIPfile(event,this.form)"></span>
</div>
&nbsp;
: <input id="uploadbutton" type="button" value="_(Upload)_" onclick="upload(this.form)" disabled><input type="button" value="_(Done)_" class="lock" onclick="done()">
</form>
</div>
@@ -0,0 +1,38 @@
Menu="Buttons:1"
Title="Switch Language"
Icon="icon-u-switch"
Code="e982"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
<?if (count(glob('/var/log/plugins/lang-*.xml'))==0):?>
// hide switch button when no other language packs
$(function(){$('.nav-item.LanguageButton').hide();});
<?endif;?>
function LanguageButton() {
var locale = '<?=$locale?>';
if (locale) {
switchLanguage('');
$.cookie('locale',locale);
} else {
switchLanguage($.cookie('locale'));
$.removeCookie('locale');
}
}
function switchLanguage(lang) {
$.post('/webGui/include/LanguageReset.php',{lang:lang},function(){location.reload();});
}
</script>
+22
View File
@@ -0,0 +1,22 @@
Menu="Buttons:6"
Title="Log"
Icon="icon-u-log"
Code="e936"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function LogButton() {
openTerminal('syslog','syslog','');
}
</script>
+25
View File
@@ -0,0 +1,25 @@
Menu="Buttons:2"
Title="Logout"
Icon="icon-u-logout"
Code="e937"
Cond="$_SERVER['HTTP_HOST']!='localhost'"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function LogoutButton() {
var id = window.setTimeout(null,0);
while (id--) window.clearTimeout(id);
window.location.href = '/logout';
}
</script>
+4
View File
@@ -0,0 +1,4 @@
Menu="Tasks:1"
Type="xmenu"
Code="e908"
Load="30"
@@ -0,0 +1,454 @@
Menu="OtherSettings"
Type="xmenu"
Title="Management Access"
Icon="icon-key"
Tag="expeditedssl"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
function find_tasks() {
global $site;
$tasks = [];
foreach ($site as $page) {
if (empty($page['Menu'])) continue;
$menu = strtok($page['Menu'], ' ');
switch ($menu[0]) {
case '$': $menu = get_ini_key($menu,strtok(' ')); break;
case '/': $menu = get_file_key($menu,strtok(' ')); break;
}
while ($menu !== false) {
if (substr($menu,0,5) == 'Tasks') {
if (empty($page['Cond'])) $tasks[] = $page['name'];
break;
}
$menu = strtok(' ');
}
}
sort($tasks);
return $tasks;
}
function acceptableCert($certFile, $hostname, $expectedURL) {
if (!file_exists($certFile)) return false;
$certURLs=null;
// get Subject URL and all SAN URLs from cert
exec("openssl x509 -noout -subject -nameopt multiline -in $certFile | sed -n 's/ *commonName *= //p' ; openssl x509 -noout -ext subjectAltName -in $certFile | grep -Eo \"DNS:[a-zA-Z 0-9.*-]*\" | sed \"s/DNS://g\"", $certURLs);
foreach($certURLs as $certURL) {
// adjust for wildcard certs
$certURL = str_replace('*', $hostname, $certURL);
// case-insensitive compare
if (strcasecmp($certURL, $expectedURL) == 0) return true;
}
return false;
}
$tasks = find_tasks();
$nginx = @parse_ini_file('/var/local/emhttp/nginx.ini') ?: [];
$addr = _var($nginx,'NGINX_LANIP') ?: _var($nginx,'NGINX_LANIP6');
$keyfile = @file_get_contents(_var($var,'regFILE'));
$cert2Issuer = '';
$isLEcert = false;
if ($keyfile !== false) $keyfile = base64_encode($keyfile);
// self-signed or user-provided cert
$cert1File = "/boot/config/ssl/certs/"._var($var,'NAME','tower')."_unraid_bundle.pem";
$cert1Present = file_exists("$cert1File");
$cert1SelfSigned = $cert1URLvalid = false;
$cert1Issuer = '&nbsp;';
if ($cert1Present) {
$cert1URL = _var($var,'NAME','tower').(_var($var,'LOCAL_TLD') ? '.'._var($var,'LOCAL_TLD') : '');
// if user replaced cert without reloading nginx, the cert on the flash could be invalid
$cert1URLvalid = acceptableCert($cert1File, _var($var,'NAME','tower'), $cert1URL);
$cert1Subject = exec("/usr/bin/openssl x509 -in $cert1File -noout -text | sed -n 's/^.*Subject: //p'");
$cert1Issuer = exec("/usr/bin/openssl x509 -in $cert1File -noout -text | sed -n -e 's/^.*Issuer: //p'");
$cert1Expires = exec("/usr/bin/openssl x509 -in $cert1File -noout -text | sed -n -e 's/^.*Not After : //p'");
$cert1SelfSigned = ($cert1Subject == $cert1Issuer);
}
// unraid.net, myunraid.net LE cert. could potentially be user provided as well
$cert2File = "/boot/config/ssl/certs/certificate_bundle.pem";
$cert2Present = file_exists("$cert2File");
if ($cert2Present) {
$cert2Subject = exec("/usr/bin/openssl x509 -in $cert2File -noout -subject -nameopt multiline 2>/dev/null|sed -n 's/ *commonName *= //p'");
$cert2Issuer = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Issuer: //p'");
$cert2Expires = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Not After : //p'");
$isLegacyCert = preg_match('/.*\.unraid\.net$/', $cert2Subject);
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $cert2Subject);
$isLEcert = $isLegacyCert || $isWildcardCert;
$subject2URL = $cert2Subject;
if ($isWildcardCert) {
if (!$addr)
// if eth0 doesn't have an IP address, then show noip.hash.myunraid.net as a placeholder url
$subject2URL = str_replace("*", 'noip', $subject2URL);
elseif (strpos($addr, ":") === false)
$subject2URL = str_replace("*", str_replace(".", "-", $addr), $subject2URL);
else
$subject2URL = str_replace("*", str_replace(":", "-", $addr), $subject2URL);
}
if ($isLEcert) {
exec("openssl x509 -checkend 2592000 -noout -in $cert2File 2>/dev/null", $arrout, $retval_expired);
if (!$addr) {
$dnsValid = false;
$dnsRebindingProtection = false;
} elseif (strpos($addr, ":") === false) {
$rebindtest_ip = exec("host -4 -t A rebindtest4.myunraid.net 2>/dev/null|awk '{print \$4}'");
$dnsRebindingProtection = ($rebindtest_ip != "192.168.42.42");
if (!$dnsRebindingProtection) {
$cert_ip = exec("host -4 -t A $subject2URL 2>/dev/null|awk '{print \$4}'");
$dnsValid = $cert_ip==$addr;
}
} else {
$rebindtest_ip = exec("host -6 -t AAAA rebindtest6.myunraid.net 2>/dev/null|awk '{print \$4}'");
// more: restore this after TTL expires
// $dnsRebindingProtection = ($rebindtest_ip != "fd42::42");
$dnsRebindingProtection = ($rebindtest_ip != "fd42::42") && ($rebindtest_ip != "fd42::");
if (!$dnsRebindingProtection) {
$cert_ip = exec("host -6 -t AAAA $subject2URL 2>/dev/null|awk '{print \$4}'");
$dnsValid = $cert_ip==$addr;
}
}
}
}
$http_port = _var($var,'PORT',80) != 80 ? ":{$var['PORT']}" : '';
$https_port = _var($var,'PORTSSL',443) != 443 ? ":{$var['PORTSSL']}" : '';
$http_ip_url = "http://"._var($nginx,'NGINX_LANIP')."{$http_port}/";
$https_ip_url = "https://"._var($nginx,'NGINX_LANIP')."{$https_port}/";
$http_ip6_url = "http://"._var($nginx,'NGINX_LANIP6')."{$http_port}/";
$https_ip6_url = "https://"._var($nginx,'NGINX_LANIP6')."{$https_port}/";
$http_mdns_url = "http://"._var($nginx,'NGINX_LANMDNS')."{$http_port}/";
$https_mdns_url = "https://"._var($nginx,'NGINX_LANMDNS')."{$https_port}/";
$https_fqdn_url = "https://"._var($nginx,'NGINX_LANFQDN')."{$https_port}/";
$https_fqdn6_url = "https://"._var($nginx,'NGINX_LANFQDN6')."{$https_port}/";
$urls = [];
// push an array of four values into the $urls array:
// 0 - the url
// 1 - the url it redirects to, or null
// 2 - the certificate file used, or null
// 3 - self-signed certificate, or false
switch(_var($var,'USE_SSL','no')) {
case 'no':
if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$http_ip_url, null, null, false];
if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$http_ip6_url, null, null, false];
if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$http_mdns_url, null, null, false];
if (!empty($nginx['NGINX_LANFQDN'])) $urls[] = [$https_fqdn_url, null, "certificate_bundle.pem", false];
if (!empty($nginx['NGINX_LANFQDN6'])) $urls[] = [$https_fqdn6_url, null, "certificate_bundle.pem", false];
break;
case 'yes':
if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$http_ip_url, $https_ip_url, null, false];
if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$https_ip_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned];
if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$http_ip6_url, $https_ip6_url, null, false];
if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$https_ip6_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned];
if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$http_mdns_url, $https_mdns_url, null, false];
if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$https_mdns_url, null, "{$var['NAME']}_unraid_bundle.pem", $cert1SelfSigned];
if (!empty($nginx['NGINX_LANFQDN'])) $urls[] = [$https_fqdn_url, null, "certificate_bundle.pem", false];
if (!empty($nginx['NGINX_LANFQDN6'])) $urls[] = [$https_fqdn6_url, null, "certificate_bundle.pem", false];
break;
case 'auto': // aka strict
if (!empty($nginx['NGINX_LANIP'])) $urls[] = [$http_ip_url, $https_fqdn_url, null, false];
if (!empty($nginx['NGINX_LANIP6'])) $urls[] = [$http_ip6_url, $https_fqdn6_url, null, false];
if (!empty($nginx['NGINX_LANMDNS'])) $urls[] = [$http_mdns_url, $https_fqdn_url, null, false];
if (!empty($nginx['NGINX_LANFQDN'])) $urls[] = [$https_fqdn_url, null, "certificate_bundle.pem", false];
if (!empty($nginx['NGINX_LANFQDN6'])) $urls[] = [$https_fqdn6_url, null, "certificate_bundle.pem", false];
break;
}
$cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replace(['%M','%R'],['%M:%S','%R:%S'],$display['time']):'');
$provisionlabel = $isLEcert ? _('Renew') : _('Provision');
$disabled_provision = $keyfile===false || ($isLEcert && $retval_expired===0) || !$addr ? 'disabled' : '';
$disabled_provision_msg = !$addr ? _('Ensure the primary network card eth0 has an IP address.') : '';
$disabled_upgrade = !$addr ? 'disabled' : '';
$disabled_updatedns = $keyfile!==false && $isLEcert ? '' : 'disabled';
$disabled_delete = $cert2Present && $var['USE_SSL']!='auto' ? '' : 'disabled';
$disabled_auto = $isLEcert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
$upgradelabel = _('Upgrade Cert');
// Get ports in use
$portsInUse = [];
exec("lsof -Pni|awk '/LISTEN/ && \$9!~/127.0.0.1/ && \$9!~/\\[::1\\]/{print \$9}'|sort -u", $output);
$bind = false; //= $var['BIND_MGT']=='yes'; - not used in 6.10
$list = ['*'];
if ($addr) array_push($list, $addr);
foreach ($output as $line) {
[$ip, $port] = my_explode($line[0]=='[' ? ']:' : ':',$line);
if ($ip[0]=='[') $ip = substr($ip,1); // ipv6 address
if (!in_array($port,$portsInUse) && (!$bind || in_array($ip,$list))) $portsInUse[] = $port;
}
sort($portsInUse,SORT_NUMERIC);
?>
<style>
span.warning{margin-left:20px}
</style>
<script>
function provisionHandler(event, form) { // provisions and renewals require being Signed In to Unraid.net
if (event.submitter.value === 'Delete') return true; // always allow deletes
if (event.submitter.value === 'Renew') return true; // always allow renewals
};
function updateDNS(button) {
$(button).prop("disabled", true).html("<i class='fa fa-circle-o-notch fa-spin fa-fw'></i>_(Update DNS)_");
var failure = function(data) {
var status = data.status;
var obj = data.responseJSON;
var msg = "_(Sorry, an error occurred updating unraid.net DNS records)_. _(The error is)_: "+obj.error+".";
$(button).prop("disabled", false).html("_(Update DNS)_");
swal({title:"_(Oops)_",text:msg,type:"error",html:true,confirmButtonText:"_(Ok)_"});
};
var success = function(data) {
$(button).prop("disabled", false).html("_(Update DNS)_");
<?$text = _('Your local IP address %s has been updated for unraid.net')?>
swal({title:"",text:"<?=sprintf($text,$addr)?>",type:"success",html:true,confirmButtonText:"_(Ok)_"});
};
$.post("/webGui/include/UpdateDNS.php",success).fail(failure);
}
function checkPorts(form) {
var portsInUse = [<?=implode(',',$portsInUse)?>];
var range = [], list = [], duplicates = [];
var checks = [
{'key':"PORTTELNET", 'used':"<?=$var['USE_TELNET']=='yes'?>", 'port':"<?=$var['PORTTELNET']?>", 'default':"23" , 'name':"_(TELNET port)_"},
{'key':"PORTSSH" , 'used':"<?=$var['USE_SSH']=='yes'?>" , 'port':"<?=$var['PORTSSH']?>" , 'default':"22" , 'name':"_(SSH port)_"},
{'key':"PORT" , 'used':"<?=$var['USE_SSL']=='no'?>" , 'port':"<?=$var['PORT']?>" , 'default':"80" , 'name':"_(HTTP port)_"},
{'key':"PORTSSL" , 'used':"<?=$var['USE_SSL']!='no'?>" , 'port':"<?=$var['PORTSSL']?>" , 'default':"443", 'name':"_(HTTPS port)_"}
];
for (var i=0,check; check=checks[i]; i++) {
var item = $(form).find('input[name="'+check['key']+'"]');
if ($(item).is(':disabled')) continue;
item.val(parseInt(item.val()));
var current = (check['port']||check['default']).toString();
var userPort = (item.val()||check['default']).toString();
if (userPort < 1 || userPort > 65535) range.push(userPort+' ('+check['name']+')');
duplicates.push(userPort);
if (check['used'] == '1' && userPort != current) {
if (portsInUse.includes(parseInt(userPort))) list.push(userPort+' ('+check['name']+')');
}
}
duplicates = duplicates.reduce(function(acc, el, i, arr) {
if (arr.indexOf(el) !== i && acc.indexOf(el) < 0) acc.push(el); return acc;
}, []);
if (range.length > 0) {
swal({title:'_(Port out of range)_',text:sprintf('_(Port %s is out of range (minimum 1 maximum 65535))_',range.join(', ')),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return;
}
if (list.length > 0) {
swal({title:'_(Port already in use)_',text:sprintf('_(Port %s is already in use by other services)_',list.join(', ')),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return;
}
if (duplicates.length > 0) {
swal({title:'_(Duplicate port entered)_',text:sprintf('_(Port %s is duplicated)_',duplicates.join(', ')),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return;
}
form.submit();
}
function updateTELNET(form) {
form.PORTTELNET.disabled = form.USE_TELNET.value=='no';
}
function updateSSH(form) {
form.PORTSSH.disabled = form.USE_SSH.value=='no';
}
$(function(){
var form = document.SSLSettings;
updateTELNET(form);
updateSSH(form);
});
</script>
<form markdown="1" name="SSLSettings" method="POST" action="/update.htm" target="progressFrame">
<input type="hidden" name="changePorts" value="Apply">
<input type="hidden" name="server_name" value="<?=strtok(_var($_SERVER,'HTTP_HOST'),":")?>">
<input type="hidden" name="server_addr" value="<?=_var($_SERVER,'SERVER_ADDR')?>">
_(User 'root')_:
: [_(Manage)_](/Settings/Users/ManagementAccess/UserEdit?name=root)
_(Start page)_:
: <select name="START_PAGE">
<?foreach ($tasks as $task) echo mk_option(_var($var,'START_PAGE','Main'), $task, _($task));?>
</select>
:mgmt_start_page_help:
<!--
Restrict access:
: <select name="BIND_MGT" class="narrow">
<?=mk_option($var['BIND_MGT'], "no", _('No'))?>
<?=mk_option($var['BIND_MGT'], "yes", _('Yes'))?>
</select>
> By default GUI, SSH and TELNET access are available on all active interfaces of the system.
>
> *Restrict access* limits GUI, SSH and TELNET access to the management interface only (eth0).
-->
_(Use TELNET)_:
: <select name="USE_TELNET" onchange="updateTELNET(this.form)">
<?=mk_option($var['USE_TELNET'], "no", _('No'))?>
<?=mk_option($var['USE_TELNET'], "yes", _('Yes'))?>
</select>
:mgmt_use_telnet_help:
_(TELNET port)_:
: <input type="number" name="PORTTELNET" class="narrow" min="1" max="65535" value="<?=$var['PORTTELNET']?>" placeholder="23">
:mgmt_telnet_port_help:
_(Use SSH)_:
: <select name="USE_SSH" onchange="updateSSH(this.form)">
<?=mk_option($var['USE_SSH'], "no", _('No'))?>
<?=mk_option($var['USE_SSH'], "yes", _('Yes'))?>
</select>
:mgmt_use_ssh_help:
_(SSH port)_:
: <input type="number" name="PORTSSH" class="narrow" min="1" max="65535" value="<?=$var['PORTSSH']?>" placeholder="22">
:mgmt_ssh_port_help:
_(Use UPnP)_:
: <select name="USE_UPNP">
<?=mk_option($var['USE_UPNP'], "yes", _('Yes'))?>
<?=mk_option($var['USE_UPNP'], "no", _('No'))?>
</select>
:mgmt_use_upnp_help:
_(Use SSL/TLS)_:
: <select name="USE_SSL" onchange="$('#ssl-warning').show();">
<?=mk_option($var['USE_SSL'], "no", _('No'))?>
<?=mk_option($var['USE_SSL'], "yes", _('Yes'))?>
<?=mk_option($var['USE_SSL'], "auto", _('Strict'), $disabled_auto)?>
</select><span id="ssl-warning" class="warning" style="display:none"><i class="fa fa-warning fa-fw"></i> _(if you have trouble logging in, close all other tabs pointing to this server and clear your browser's cache)_</span>
:mgmt_use_ssl_tls_help:
_(HTTP port)_:
: <input type="number" name="PORT" class="narrow" min="1" max="65535" value="<?=$var['PORT']?>" placeholder="80">
:mgmt_http_port_help:
_(HTTPS port)_:
: <input type="number" name="PORTSSL" class="narrow" min="1" max="65535" value="<?=$var['PORTSSL']?>" placeholder="443">
:mgmt_https_port_help:
_(Local TLD)_:
: <input type="text" name="LOCAL_TLD" class="narrow" value="<?=htmlspecialchars($var['LOCAL_TLD'])?>">
:mgmt_local_tld_help:
&nbsp;
: <input type="button" value="_(Apply)_" onclick="checkPorts(this.form)" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
_(Local access URLs)_:
: <?
// url[0] = url
// url[1] = redirect url or null
// url[2] = certificate used or null
// url[3] = is certificate self-signed T/F
$n = 0;
foreach($urls as $url) {
$msg = "";
$url0 = substr_count($url[0]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[0]) : $url[0]; // IPv6 - IPv4 notation
$url1 = substr_count($url[1]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[1]) : $url[1]; // IPv6 - IPv4 notation
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url1'>$url1</a>";
if ($url[2]) $msg .= " "._("uses")." ".$url[2];
if ($url[3]) $msg .= "<span class='warning'> <i class='fa fa-warning fa-fw'></i> "._("is a self-signed certificate, ignore the browser's warning and proceed to the GUI")."</span>";
echo ($n ? "<dt>&nbsp;</dt><dd>" : ""),"<a href='$url0'>$url0</a>$msg",($n++ ? "</dd>" : "");
}?>
:mgmt_local_access_urls_help:
<?if ($cert1Present):?>
_(Self-signed or user-provided certificate)_:
: <?=$cert1File?>
<?if ($cert1URLvalid && _var($var,'USE_SSL')=='yes'):?>
_(Certificate URL)_:
: <?="<a href='https://$cert1URL$https_port'>$cert1URL</a>"?>
<?elseif ($cert1URLvalid):?>
_(Certificate URL)_:
: <?=$cert1URL?>
<?else:?>
_(Certificate URL)_:
: _(Certificate not valid for)_ <?=$cert1URL?>
<?endif;?>
_(Certificate issuer)_:
: <?=$cert1Issuer?>
<?if ($cert1URLvalid && _var($var,'USE_SSL')=='yes' && $cert1SelfSigned):?>
<span class="warning"><i class="fa fa-warning fa-fw"></i> _(is a self-signed certificate, ignore the browser's warning when using this certificate)_</span>
<?endif;?>
_(Certificate expiration)_:
: <?=_(my_date($cert_time_format, strtotime($cert1Expires)),0)?>
<?else:?>
_(Self-signed certificate file)_:
: _(Not present)_
<?endif;?>
<form markdown="1" name="Provision" method="POST" target="progressFrame" action="/update.htm" onsubmit="provisionHandler(event, this)">
<input type="hidden" name="server_name" value="<?=strtok(_var($_SERVER,'HTTP_HOST'),":")?>">
<input type="hidden" name="server_addr" value="<?=_var($_SERVER,'SERVER_ADDR')?>">
<?if ($cert2Present):?>
_(Unraid Let's Encrypt certificate)_:
: <?=$cert2File?>
_(Certificate URL)_:
: <?="<a href='https://$subject2URL$https_port'>$cert2Subject</a>"?>
_(Certificate issuer)_:
: <?=$cert2Issuer?>
_(Certificate expiration)_:
: <?=_(my_date($cert_time_format, strtotime($cert2Expires)),0)?>
<?if ($dnsRebindingProtection):?>
&nbsp;
: _(DNS Rebinding Protection is ENABLED)_
<?elseif ($dnsValid !== true):?>
&nbsp;
: _(DNS Propagation is PENDING)_
<?endif;?>
<?else:?>
_(CA-signed certificate file)_:
: _(Not present)_
<?endif;?>
&nbsp;
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><!-- <button type="button" onclick="updateDNS(this)" <?=$disabled_updatedns?>>_(Update DNS)_</button> --><?=$disabled_provision_msg?>
<?if ($cert2Present && $isLegacyCert):?>
&nbsp;
: <button type="submit" name="changePorts" value="Upgrade" <?=$disabled_upgrade?>><?=$upgradelabel?></button>
<?endif;?>
:mgmt_certificate_expiration_help:
</form>
+133
View File
@@ -0,0 +1,133 @@
Menu="Scheduler:2"
Title="Mover Settings"
Tag="calendar-check-o"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$setup = true;
if (!$pool_devices) {
echo "<p class='notice'>"._('No Cache device present')."!</p>";
$setup = false;
} elseif ($var['shareUser']=='-') {
echo "<p class='notice'>"._('User shares not enabled')."!</p>";
$setup = false;
}
$cron = explode(' ',$var['shareMoverSchedule']);
$move = $cron[2]!='*' ? 3 : ($cron[4]!='*' ? 2 : (substr($cron[1],0,1)!='*' ? 1 : 0));
$mode = ['Hourly','Daily','Weekly','Monthly'];
$days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
?>
<script>
<? if ($setup == true):?>
$(function() {
presetMover(document.mover_schedule);
});
<? endif; ?>
// Fool Unraid by simulating the original input field
function prepareMover(form) {
var mode = form.shareMoverSchedule.value;
var min = mode!=0 ? form.min.value : 0;
var hour = mode!=0 ? form.hour1.value : form.hour2.value;
form.shareMoverSchedule.options[mode].value = min+' '+hour+' '+form.dotm.value+' * '+form.day.value;
form.min.disabled = true;
form.hour1.disabled = true;
form.hour2.disabled = true;
form.dotm.disabled = true;
form.day.disabled = true;
}
function presetMover(form) {
var mode = form.shareMoverSchedule.value;
form.min.disabled = false;
form.day.disabled = mode!=2;
form.dotm.disabled = mode!=3;
form.day.value = form.day.disabled ? '*' : (form.day.value=='*' ? 0 : form.day.value);
form.dotm.value = form.dotm.disabled ? '*' : (form.dotm.value=='*' ? 1 : form.dotm.value);
if (mode==0) {$('#H1').hide(); $('#H2').show();} else {$('#H2').hide(); $('#H1').show();}
}
</script>
<form markdown="1" name="mover_schedule" method="POST" action="/update.htm" target="progressFrame" onsubmit="prepareMover(this)">
<?if ($setup):?>
_(Mover schedule)_:
: <select name="shareMoverSchedule" onchange="presetMover(this.form)">
<?for ($m=0; $m<count($mode); $m++):?>
<?=mk_option($move, strval($m), _($mode[$m]))?>
<?endfor;?>
</select>
:mover_schedule_help:
_(Day of the week)_:
: <select name="day">
<?for ($d=0; $d<count($days); $d++):?>
<?=mk_option($cron[4], strval($d), _($days[$d],0))?>
<?endfor;?>
<?=mk_option($cron[4], "*", "--------", "disabled")?>
</select>
:mover_day_of_the_week_help:
_(Day of the month)_:
: <select name="dotm">
<?for ($d=1; $d<=31; $d++):?>
<?=mk_option($cron[2], strval($d), sprintf("%02d", $d))?>
<?endfor;?>
<?=mk_option($cron[2], "*", "--------", "disabled")?>
</select>
:mover_day_of_the_month_help:
_(Time of the day)_:
: <span id="H1"<?if ($move==0):?> style="display:none"<?endif;?>><select name="hour1" class="narrow">
<?for ($d=0; $d<=23; $d++):?>
<?=mk_option($cron[1], strval($d), sprintf("%02d", $d))?>
<?endfor;?>
</select>
<select name="min" class="narrow">
<?for ($d=0; $d<=55; $d+=5):?>
<?=mk_option($cron[0], strval($d), sprintf("%02d", $d))?>
<?endfor;?>
</select>&nbsp;&nbsp;_(HH:MM)_</span>
: <span id="H2"<?if ($move!=0):?> style="display:none"<?endif;?>><select name="hour2">
<?=mk_option($cron[1], "*/1", _("Every hour"))?>
<?=mk_option($cron[1], "*/2", _("Every 2 hours"))?>
<?=mk_option($cron[1], "*/3", _("Every 3 hours"))?>
<?=mk_option($cron[1], "*/4", _("Every 4 hours"))?>
<?=mk_option($cron[1], "*/6", _("Every 6 hours"))?>
<?=mk_option($cron[1], "*/8", _("Every 8 hours"))?>
</select></span>
:mover_time_of_the_day_help:
_(Mover logging)_:
: <select name="shareMoverLogging">
<?=mk_option($var['shareMoverLogging'], "yes", _("Enabled"))?>
<?=mk_option($var['shareMoverLogging'], "no", _("Disabled"))?>
</select>
:mover_logging_help:
<?endif;?>
<?if ($setup):?>
<?if ($pool_devices):?>
<?if (file_exists('/var/run/mover.pid')):?>
<input type="submit" name="cmdStartMover" value="_(Move now)_" disabled> _(Mover is running)_
<?else:?>
<input type="submit" name="cmdStartMover" value="_(Move now)_"> _(Click to invoke the Mover)_
<?endif;?>
<?else:?>
&nbsp;
<?endif;?>
: <input type="submit" name="changeMover" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
<?endif;?>
</form>
+42
View File
@@ -0,0 +1,42 @@
Menu="NetworkServices:2"
Title="NFS"
Icon="icon-linux"
Tag="linux"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function checkNFSenable() {
var form = document.nfs_enable;
form.fuse_remember.disabled = form.shareNFSEnabled.value=="_(no)_";
}
$(checkNFSenable);
</script>
<form markdown="1" name="nfs_enable" method="POST" action="/update.htm" target="progressFrame">
_(Enable NFS)_:
: <select name="shareNFSEnabled" onchange="checkNFSenable()">
<?=mk_option($var['shareNFSEnabled'], "no", _('No'));?>
<?=mk_option($var['shareNFSEnabled'], "yes", _('Yes'));?>
</select>
:nfs_enable_help:
_(Tunable (fuse_remember))_:
: <input type="text" name="fuse_remember" maxlength="10" value="<?=$var['fuse_remember']?>" class="narrow"><?=_($var['fuse_remember_status'])?>
:nfs_tunable_fuse_remember_help:
&nbsp;
: <input type="submit" name="changeShare" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
+116
View File
@@ -0,0 +1,116 @@
Menu="NetworkSettings"
Title="Interface Extra"
Tag="icon-ethernet"
---
<?PHP
/* Copyright 2023, Lime Technology
* Copyright 2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$cfg = '/boot/config/network-extra.cfg';
if (file_exists($cfg)) {
extract(parse_ini_file($cfg));
$include_interfaces = str_replace(" ","\n",$include_interfaces);
$exclude_interfaces = str_replace(" ","\n",$exclude_interfaces);
} else {
$include_interfaces = "";
$exclude_interfaces = "";
}
?>
<style>
span[id^="info-"]{margin-left:20px}
<?if ($themes1):?>
span.status.vhshift{margin-right:-10px!important}
<?endif;?>
</style>
<script>
function prepareText(form) {
var mgmt = ['br0','bond0','eth0'];
form.include_interfaces.value = form.include.value.replace(/[\n,]/g,' ').replace(/ +/g,' ').trim();
form.exclude_interfaces.value = form.exclude.value.replace(/[\n,]/g,' ').replace(/ +/g,' ').trim();
form.include.disabled = true;
form.exclude.disabled = true;
var include = form.include_interfaces.value.split(' ');
var exclude = form.exclude_interfaces.value.split(' ');
// silently remove management interfaces from include list
for (var i=0,name; name=include[i]; i++) {
if (mgmt.includes(name)) include[i] = '';
}
form.include_interfaces.value = include.join(' ').replace(/ +/g,' ').trim();
// give warning when management interface is excluded
for (var i=0,name; name=exclude[i]; i++) {
if (mgmt.includes(name)) {
swal({title:"_(Management Interface)_ '"+name+"'",text:"_(You can not exclude this interface)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
form.include.disabled = false;
form.exclude.disabled = false;
return false;
}
}
return true;
}
<?if (!$tabbed):?>
function toggleExtra() {
var tag = '#tag_extra';
var view = '#extra_table';
if ($(view).is(':visible')) {
$(tag).removeClass('fa-chevron-up').addClass('fa-chevron-down');
$.cookie(view,'hide',{expires:3650});
} else {
$(tag).removeClass('fa-chevron-down').addClass('fa-chevron-up');
$.removeCookie(view);
}
$(view).toggle('slow');
}
$(function(){
$('div.title').eq(-3).find('span.left').append("<span class='status vhshift'><i id='tag_extra' class='fa fa-fw fa-chevron-up' style='cursor:pointer' onclick='toggleExtra()'></i></span>");
if (!$.cookie('#extra_table')) $('#extra_table').show(); else {$('#extra_table').hide(); $('#tag_extra').removeClass('fa-chevron-up').addClass('fa-chevron-down');}
});
<?else:?>
$(function(){
$('#extra_table').show();
});
<?endif;?>
$(function(){
$('form textarea').on('input',function(){
$(this).prop('rows',($(this).val().match(/\n/g)||[]).length+1);
});
});
</script>
<div markdown="1" id="extra_table" style="display:none">
<form markdown="1" name="network_extra" method="POST" action="/update.php" target="progressFrame" onsubmit="return prepareText(this)">
<input type="hidden" name="#file" value="<?=$cfg?>">
<input type="hidden" name="#command" value="/webGui/scripts/reload_services">
<input type="hidden" name="include_interfaces" value="">
<input type="hidden" name="exclude_interfaces" value="">
_(Current listening interfaces)_:
: <?=exec("$docroot/webGui/scripts/show_interfaces")?:_('Any')?>
<hr>
_(Include listening interfaces)_:
: <textarea name="include" spellcheck="false" cols="80" rows="<?=substr_count($include_interfaces,"\n")+1?>" maxlength="2048" name="text" style="resize:none;width:200px"><?=$include_interfaces?></textarea>
:eth_network_extra_include_help:
_(Exclude listening interfaces)_:
: <textarea name="exclude" spellcheck="false" cols="80" rows="<?=substr_count($exclude_interfaces,"\n")+1?>" maxlength="2048" name="text" style="resize:none;width:200px"><?=$exclude_interfaces?></textarea>
:eth_network_extra_exclude_help:
&nbsp;
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
</div>
+110
View File
@@ -0,0 +1,110 @@
Menu="NetworkSettings"
Title="Interface Rules"
Tag="icon-network"
Cond="file_exists('/boot/config/network-rules.cfg')"
---
<?PHP
/* Copyright 2023, Lime Technology
* Copyright 2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$cfg = '/boot/config/network-rules.cfg';
function strip($item) {
[$key,$val] = explode('"',$item);
return $val;
}
exec("awk '/NAME=\"eth/{print $4 $8}' $cfg",$rules);
exec("grep -Po '^# \K.*' $cfg",$info);
$link = []; $i = 0;
foreach ($rules as $rule) {
[$mac,$eth] = array_map('strip',my_explode(',',$rule));
$link[$eth]['mac'] = $mac;
$link[$eth]['info'] = $info[$i++];
}
ksort($link,SORT_NATURAL);
?>
<style>
span[id^="info-"]{margin-left:20px}
<?if ($themes1):?>
span.status.vhshift{margin-right:-10px!important}
<?endif;?>
</style>
<script>
var info = {};
<?foreach ($link as $eth => $val):?>
info['<?='_'.str_replace(':','',$val['mac'])?>'] = "<?=$val['info']?>";
<?endforeach;?>
function check_rules(form) {
var mac = [];
$(form).find('select[name^="eth"]').each(function(){mac.push($(this).val());});
if (mac.same()) {
swal({title:"_(MAC address mismatch)_",text:"_(Rules contain duplicate MAC address assignments)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
} else {
return true;
}
}
function update_info(id,mac) {
$('#info-'+id).html(info['_'+mac.replace(/:/g,'')]);
}
<?if (!$tabbed):?>
function toggleRules() {
var tag = '#tag_rules';
var view = '#rules_table';
if ($(view).is(':visible')) {
$(tag).removeClass('fa-chevron-up').addClass('fa-chevron-down');
$.cookie(view,'hide',{expires:3650});
} else {
$(tag).removeClass('fa-chevron-down').addClass('fa-chevron-up');
$.removeCookie(view);
}
$(view).toggle('slow');
}
$(function(){
$('div.title').eq(-2).find('span.left').append("<span class='status vhshift'><i id='tag_rules' class='fa fa-fw fa-chevron-up' style='cursor:pointer' onclick='toggleRules()'></i></span>");
if (!$.cookie('#rules_table')) $('#rules_table').show(); else {$('#rules_table').hide(); $('#tag_rules').removeClass('fa-chevron-up').addClass('fa-chevron-down');}
});
<?else:?>
$(function(){
$('#rules_table').show();
});
<?endif;?>
</script>
<div markdown="1" id="rules_table" style="display:none">
<form markdown="1" name="network_rules" method="POST" action="/update.php" target="progressFrame" onsubmit="return check_rules(this)">
<input type="hidden" name="#file" value="not-used">
<input type="hidden" name="#include" value="/webGui/include/update.rules.php">
<input type="hidden" name="#cfg" value="<?=$cfg?>">
<?foreach ($link as $eth => $file):?>
_(Interface)_ <?=$eth?>:
: <select name="<?=$eth?>" onchange="update_info(this.name,this.value)">
<?foreach ($link as $my => $val):?>
<?=mk_option($file['mac'],$val['mac'],strtoupper($val['mac']));?>
<?endforeach;?>
</select><span id="info-<?=$eth?>"><?=$file['info']?></span>
<?endforeach;?>
&nbsp;
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
:eth_network_rules_help:
<?if (file_exists('/tmp/network-rules.tmp')):?>
<br><span class="error" style="text-align:center;padding:12px 0">_(Please **Reboot** system to make new rules active)_</span>
<?endif;?>
</div>
@@ -0,0 +1,4 @@
Menu="Settings:2"
Type="menu"
Title="Network Services"
Tag="globe"
@@ -0,0 +1,4 @@
Menu="OtherSettings"
Type="xmenu"
Title="Network Settings"
Icon="icon-network"
+2
View File
@@ -0,0 +1,2 @@
Type="xmenu"
Tabs="true"
+84
View File
@@ -0,0 +1,84 @@
Menu="UNRAID-OS"
Title="New Config"
Icon="icon-config"
Tag="cog"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$newarray = $var['mdState']=='NEW_ARRAY';
$disabled = $var['fsState']=="Started";
$width = [166,300];
if ($newarray) {
@unlink('/boot/config/smart-one.cfg');
@unlink('/boot/config/smart-all.cfg');
@unlink('/boot/config/plugins/dynamix/monitor.ini');
foreach ($pools as $pool) @unlink("/var/tmp/$pool.log.tmp");
}
?>
<style>
span.indent{display:inline-block;width:240px;margin-top:30px}
</style>
<script>
function prepareNewConfig(form) {
for (var i=1,item; item=form.preset.options[i]; i++) {
switch (item.value) {
case 'array': if (item.selected) form.preserveArray.disabled = false; break;
case 'cache' : if (item.selected) form.preserveCache.disabled = false; break;
}
}
form.preset.disabled = true;
}
$(function() {
$('#s1').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>, firstItemChecksAll:true, explicitClose:"..._(close)_"});
<?if ($disabled):?>
$('#s1').dropdownchecklist('disable');
<?endif;?>
});
</script>
:newconfig_plug:
This is a utility to reset the array disk configuration so that all disks appear as "New" disks, as
if it were a fresh new server.
This is useful when you have added or removed multiple drives and wish to rebuild parity based on
the new configuration.
Use the *'Preserve current assignments'* selection to populate the desired disk slots ***after*** the array has been reset. By default **no** disk slots are populated.
**DO NOT USE THIS UTILITY THINKING IT WILL REBUILD A FAILED DRIVE** - it will have the opposite
effect of making it ***impossible*** to rebuild an existing failed drive - you have been warned!
:end
<hr>
<form name="newConfig" method="POST" action="/update.htm" target="progressFrame" onsubmit="prepareNewConfig(this)">
<input type="hidden" name="preserveArray" value="yes" disabled>
<input type="hidden" name="preserveCache" value="yes" disabled>
<span class="indent">_(Preserve current assignments)_:</span>
<select id="s1" name="preset" multiple="multiple" style="display:none">
<option value=''>_(All)_</option>
<?=mk_option_check(0,'array',_('Array slots'))?>
<?=mk_option_check(0,'cache',_('Pool slots'))?>
</select>
<br>
<span class="indent"><input type="submit" class="lock" name="cmdInit" value="_(Apply)_" disabled><input type="button" class="lock" value="_(Done)_" onclick="done()"></span>
<?if ($newarray):?>
_(Array has been **Reset**)_ (_(please configure)_)
<?elseif ($disabled):?>
_(Array must be **Stopped** to change)_
<?else:?>
<input type="checkbox" onClick="cmdInit.disabled=!this.checked"><small>_(Yes, I want to do this)_</small>
<?endif;?>
</form>
+133
View File
@@ -0,0 +1,133 @@
Menu="UNRAID-OS"
Title="New Permissions"
Icon="icon-permissions"
Tag="folder-o"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$width = [166,300];
function data_disks($disk) {
global $pools;
return (_var($disk,'type')=="Data" || (_var($disk,'type')=="Cache" && in_array(_var($disk,'name'),$pools))) && _var($disk,'status')=='DISK_OK';
}
?>
<style>
span.block{display:inline-block;width:300px;margin:24px 0}
pre.pre{margin:30px 0;padding:20px}
pre>p{margin:0;padding:0}
</style>
<script>
function selection(select,remove) {
if (remove) {
$('#s1').dropdownchecklist('destroy');
$('#s2').dropdownchecklist('destroy');
}
if (select==0) {$('#disks').show(); $('#shares').hide();} else {$('#shares').show(); $('#disks').hide();}
$('#s1').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>, firstItemChecksAll:true, explicitClose:"..._(close)_"});
$('#s2').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>, firstItemChecksAll:true, explicitClose:"..._(close)_"});
<?if ($var['fsState']!="Started"):?>
$('#s1').dropdownchecklist('disable');
$('#s2').dropdownchecklist('disable');
<?endif;?>
}
function setNewPerms(form) {
var dirs = [];
if (form.select.value==0) {
for (var i=1,item; item=form.disks.options[i]; i++) {
if (item.selected) dirs.push(item.value);
}
} else {
for (var i=1,item; item=form.shares.options[i]; i++) {
if (item.selected) dirs.push(item.value);
}
}
dirs = dirs.join('*');
if (dirs) {
swal({title:"_(Proceed)_?",text:"_(This will update folder & file permissions)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},
function(){setTimeout(function(){openPlugin('newperms '+encodeURIComponent(dirs),"_(New Permissions)_");},250);
});
}
}
$(function() {
selection(0,false);
});
</script>
:newperms_1_plug:
This is a mandatory one-time action to be taken after upgrading from a pre-5.0 Unraid server release to Unraid v5 or a later release.
Select **ALL DISKS** when performing this one-time action.
This utility is also useful for restoring default ownership/permissions on files and
directories when transitioning back from Active Directory to non-Active Directory integration.
The utility starts a background process that goes to each of your data disks and cache disks and selected user shares
and changes file and directory ownership to *nobody/users* (i.e., uid/gid to 99/100), and sets permissions
as follows:
:end
<pre class="pre">
:newperms_2_plug:
For directories:
drwxrwxrwx
For read/write files:
-rw-rw-rw-
For readonly files:
-r--r--r--
:end
</pre>
:newperms_3_plug:
Clicking **Start** will open another window and start the background process.
Closing the window before completion will terminate the background process - so don't do that. This process can take a long time if you have many files.
Note that this tool may negatively affect any docker containers if you allow your **appdata** share to be included.
:end
<form method="POST" action="/update.htm" target="progressFrame">
<span class="block">
<select name="select" onchange="selection(this.value,true)">
<?=mk_option(0,"0","_(Disks)_")?>
<?=mk_option(0,"1","_(Shares)_")?>
</select>
</span>
<span id="disks" class="block">
<select id="s1" name="disks" style="display:none" multiple>
<option value=''>_(All)_</option>
<?foreach (array_filter($disks,'data_disks') as $disk):?>
<?=mk_option(1,"/mnt/{$disk['name']}",_(my_disk($disk['name'])),3)?>
<?endforeach;?>
</select>
</span>
<span id="shares" class="block" style="display:none">
<select id="s2" name="shares" style="display:none" multiple>
<option value=''>_(All)_</option>
<?uksort($shares,'strnatcasecmp');?>
<?foreach ($shares as $share):?>
<?=mk_option(1,"/mnt/user/{$share['name']}",$share['name'])?>
<?endforeach;?>
</select>
</span>
<?if (_var($var,'fsState')=="Started"):?>
<div><input type="button" value="_(Start)_" onclick="setNewPerms(this.form)"><input type="button" value="_(Done)_" class="lock" onclick="done()"></div>
<?else:?>
<div><input type="button" value="_(Start)_" disabled><input type="button" value="_(Done)_" class="lock" onclick="done()">_(Array must be **Started** to change permissions)_.</div>
<?endif;?>
</form>
@@ -0,0 +1,159 @@
Menu="Notifications:3"
Title="Notification Agents"
Tag="rss-square"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
var scripts = new Object();
var enabledAgents = new Object();
var disabledAgents = new Object();
var openPage = true;
<?$width = [166,300]?>
<?if ($tabbed):?>
$('#tab3').bind({click:function(){initDropdown();}});
$(function(){if ($('#tab3').is(':checked')) initDropdown();});
<?else:?>
$(function(){initDropdown();});
<?endif;?>
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
};
}
function addSlashes(text) {
return text.replace(/\"/g, "\\\"");
}
function prepareService(el, name) {
var script = scripts[name];
var vars = "";
var form = $(el).parents('form:first');
form.find('.variable').each(function() {
vars += $(this).attr('name')+'="'+addSlashes($(this).val())+"\"\n";
});
$('[name="'+name+'"] [id^="slot_"]').each(function() {
var include = '';
$(this).find('option').each(function() {
if ($(this).is(':selected')) {
if (include.length) include += '\\n';
include += $(this).val();
$(this).removeAttr('selected');
}
});
vars += $(this).attr('name')+'="'+include+"\"\n";
});
var cmd = (form.find('select[name="Enabled"]').val()=='yes' ? 'enable' : 'disable');
form.find('input[name="#arg\\[1\\]"]').val(cmd);
form.find('input[name="#arg\\[2\\]"]').val(name+'.sh');
form.find('input[name="text"]').val(script.format(vars,'\n'));
}
function execCmd(cmd, name) {
var form = $('#formExec');
form.find('input[name="#arg\\[1\\]"]').val(cmd);
if (name) form.find('input[name="#arg\\[2\\]"]').val(name+'.sh');
form.submit();
}
function testService(name) {
var form = $('#formExec');
form.find('input[name="#arg\\[1\\]"]').val('test');
form.find('input[name="#arg\\[2\\]"]').val(name+'.sh');
form.append('<input type="hidden" name="#env[]" value="EVENT='+name+' test.">');
form.append('<input type="hidden" name="#env[]" value="SUBJECT='+name+' test.">');
form.append('<input type="hidden" name="#env[]" value="DESCRIPTION='+name+' test.">');
form.append('<input type="hidden" name="#env[]" value="IMPORTANCE=normal">');
// host is normally added to link by the notify script. add it here since calling the agent directly.
form.append('<input type="hidden" name="#env[]" value="LINK='+window.location.origin+'/Settings/Notifications">');
form.submit();
}
function initDropdown() {
if (openPage) {$("[id^='slot_']").dropdownchecklist({width:<?=$width[1]?>,explicitClose:'..._(close)_'}); openPage = false;}
}
</script>
<form method="POST" id="formExec" action="/update.php" target="progressFrame">
<input type="hidden" name="#command" value="/webGui/scripts/agent">
<input type="hidden" name="#arg[1]" value="">
<input type="hidden" name="#arg[2]" value="">
</form>
<?
$fields = ['Event','Subject','Timestamp','Description','Importance','Content','Link'];
$xml_file = "webGui/include/NotificationAgents.xml";
$xml = @simplexml_load_file($xml_file) or die(_("Failed to open")." $xml_file");
$i = 1;
foreach ($xml->Agent as $agent) {
$name = str_replace(' ','_',$agent->Name);
$enabledAgent = agent_fullname("$name.sh", "enabled");
$disabledAgent = agent_fullname("$name.sh", "disabled");
if (is_file($disabledAgent)) {
$file = $disabledAgent;
if (is_file($enabledAgent)) unlink($enabledAgent);
} else {
$file = $enabledAgent;
}
$values = [];
$script = "";
if (is_file($file)) {
preg_match("/[#]{6,100}([^#]*?)[#]{6,100}/si", file_get_contents($file), $match);
if (isset($match[1])) {
foreach (explode(PHP_EOL, $match[1]) as $line) {
if (strpos($line, "=")) {
[$k, $v] = my_explode("=",str_replace("\"", "", $line),2);
$values[$k] = $v;
}
}
}
}
foreach (explode(PHP_EOL,(String) $agent->Script) as $line) if (trim($line)) $script .= trim($line)."{1}";
echo '<div class="title shift"><span class="left"><img src="/plugins/dynamix/icons/'.strtolower(str_replace('_','',$name)).'.png" class="icon" style="height:16px;width:16px;">'.str_replace('_',' ',$name).'</span><span class="status vhshift">'.(is_file($enabledAgent) ? '<span class="green">'._("Enabled").'</span>' : '<span class="red">'._("Disabled").'</span>').'</span></div>';
echo '<form method="POST" name="'.$name.'" action="/update.php" target="progressFrame">';
echo '<input type="hidden" name="#include" value="/webGui/include/update.file.php">';
echo '<input type="hidden" name="#file" value="'.$file.'">';
echo '<input type="hidden" name="#command" value="/webGui/scripts/agent">';
echo '<input type="hidden" name="#arg[1]" value="">';
echo '<input type="hidden" name="#arg[2]" value="">';
echo '<input type="hidden" name="text" value="">';
echo '<dl><dt>'._("Agent function").':</dt><dd><select name="Enabled">';
echo mk_option(is_file($disabledAgent), 'no', _('Disabled'));
echo mk_option(is_file($enabledAgent), 'yes', _('Enabled'));
echo '</select></dd></dl>';
echo '<script>scripts["'.$name.'"]='.json_encode($script).';enabledAgents["'.$name.'"]="'.$enabledAgent.'";disabledAgents["'.$name.'"]="'.$disabledAgent.'";</script>';
foreach ($agent->Variables->children() as $v) {
$vName = preg_replace('#\[([^\]]*)\]#', '<$1>', (string) $v);
$vDesc = ucfirst(strtolower(preg_replace('#\[([^\]]*)\]#', '<$1>', $v->attributes()->Desc)));
$vDefault = preg_replace('#\[([^\]]*)\]#', '<$1>', $v->attributes()->Default);
$vHelp = preg_replace('#\[([^\]]*)\]#', '<$1>', $v->attributes()->Help);
echo "<dl><dt>$vDesc:</dt><dd>";
if (preg_match('/title|message/', $vDesc)) {
echo '<select id="slot_'.$i++.'" name="'.$vName.'" multiple style="display:none">';
$value = str_replace('\n',',',isset($values[$vName]) ? $values[$vName] : $vDefault);
foreach ($fields as $field) echo mk_option_check($value,'$'.strtoupper($field),_($field));
echo '</select>';
} else {
echo '<input type="text" name="'.$vName.'" class="variable" required value="'.( isset($values[$vName]) ? $values[$vName] : $vDefault ).'">';
}
echo '</dd></dl>';
if ($vHelp) echo '<blockquote class="inline_help">'.$vHelp.'</blockquote>';
}
echo '<dl><dt>&nbsp;</dt><dd><input type="submit" value='._("Apply").' onclick="prepareService(this, \''.$name.'\')" disabled>';
echo '<input type="button" value='._("Done").' onclick="done()">';
if (is_file($file)) {
echo '<input type="button" value='._("Delete").' onclick="execCmd(\'delete\',\''.$name.'\')">';
echo '<input type="button" value='._("Test").' onclick="testService(\''.$name.'\')"'.($file==$enabledAgent ? '>' : ' disabled>');
}
echo '</dd></dl></form><div style="min-height:50px;"></div>';
}
?>
+285
View File
@@ -0,0 +1,285 @@
Menu="UserPreferences"
Type="xmenu"
Title="Notification Settings"
Icon="icon-notifications"
Tag="phone-square"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
* Copyright 2012, Andrew Hamer-Adams, http://www.pixeleyes.co.nz.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$events = explode('|', $notify['events'] ?? '');
$disabled = $notify['system'] ? '' : 'disabled';
?>
<style>
select.a{min-width:220px}
span.a{display:inline-block;width:220px;font-style:italic}
</style>
<script>
function prepareNotify(form) {
form.entity.value = form.normal1.checked | form.warning1.checked | form.alert1.checked;
form.normal.value = form.normal1.checked*1 + form.normal2.checked*2 + form.normal3.checked*4;
form.warning.value = form.warning1.checked*1 + form.warning2.checked*2 + form.warning3.checked*4;
form.alert.value = form.alert1.checked*1 + form.alert2.checked*2 + form.alert3.checked*4;
form.unraid.value = form.unraid1.checked*1 + form.unraid2.checked*2 + form.unraid3.checked*4;
form.plugin.value = form.plugin1.checked*1 + form.plugin2.checked*2 + form.plugin3.checked*4;
form.docker_notify.value = form.docker_notify1.checked*1 + form.docker_notify2.checked*2 + form.docker_notify3.checked*4;
form.language_notify.value = form.language_notify1.checked*1 + form.language_notify2.checked*2 + form.language_notify3.checked*4;
form.report.value = form.report1.checked*1 + form.report2.checked*2 + form.report3.checked*4;
form.normal1.disabled = true;
form.normal2.disabled = true;
form.normal3.disabled = true;
form.warning1.disabled = true;
form.warning2.disabled = true;
form.warning3.disabled = true;
form.alert1.disabled = true;
form.alert2.disabled = true;
form.alert3.disabled = true;
form.unraid1.disabled = true;
form.unraid2.disabled = true;
form.unraid3.disabled = true;
form.plugin1.disabled = true;
form.plugin2.disabled = true;
form.plugin3.disabled = true;
form.docker_notify1.disabled = true;
form.docker_notify2.disabled = true;
form.docker_notify3.disabled = true;
form.language_notify1.disabled = true;
form.language_notify2.disabled = true;
form.language_notify3.disabled = true;
form.report1.disabled = true;
form.report2.disabled = true;
form.report3.disabled = true;
}
function prepareSystem(index) {
if (index==0) $('.checkbox').attr('disabled','disabled'); else $('.checkbox').removeAttr('disabled');
}
function prepareTitle() {
var title = '_(Available notifications)_:';
$('#unraidTitle,#pluginTitle,#dockerTitle,#languageTitle,#reportTitle').html('&nbsp;');
if ($('.unraid').is(':visible')) {$('#unraidTitle').html(title); return;}
if ($('.plugin').is(':visible')) {$('#pluginTitle').html(title); return;}
if ($('.docker').is(':visible')) {$('#dockerTitle').html(title); return;}
if ($('.language').is(':visible')) {$('#languageTitle').html(title); return;}
if ($('.report').is(':visible')) {$('#reportTitle').html(title); return;}
}
function prepareUnraid(value) {
if (value=='') $('.unraid').hide(); else $('.unraid').show();
prepareTitle();
}
function preparePlugin(value) {
if (value=='') $('.plugin').hide(); else $('.plugin').show();
prepareTitle();
}
function prepareDocker(value) {
if (value=='') $('.docker').hide(); else $('.docker').show();
prepareTitle();
}
function prepareLanguage(value) {
if (value=='') $('.language').hide(); else $('.language').show();
prepareTitle();
}
function prepareReport(value) {
if (value=='') $('.report').hide(); else $('.report').show();
prepareTitle();
}
$(function(){
prepareUnraid(document.notify_settings.unraidos.value);
preparePlugin(document.notify_settings.version.value);
prepareDocker(document.notify_settings.docker_update.value);
prepareLanguage(document.notify_settings.language_update.value);
prepareReport(document.notify_settings.status.value);
});
</script>
<form markdown="1" name="notify_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareNotify(this)">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg">
<input type="hidden" name="#section" value="notify">
<input type="hidden" name="#command" value="/webGui/scripts/notify">
<input type="hidden" name="#arg[1]" value="cron-init">
<input type="hidden" name="entity">
<input type="hidden" name="normal">
<input type="hidden" name="warning">
<input type="hidden" name="alert">
<input type="hidden" name="unraid">
<input type="hidden" name="plugin">
<input type="hidden" name="docker_notify">
<input type="hidden" name="language_notify">
<input type="hidden" name="report">
_(Notifications display)_:
: <select class="a" name="display">
<?=mk_option($notify['display'], "0", _("Detailed"))?>
<?=mk_option($notify['display'], "1", _("Summarized"))?>
</select>
:notifications_display_help:
_(Date format)_:
: <select name="date" class="a">
<?=mk_option($notify['date'], "d-m-Y", _("DD-MM-YYYY"))?>
<?=mk_option($notify['date'], "m-d-Y", _("MM-DD-YYYY"))?>
<?=mk_option($notify['date'], "Y-m-d", _("YYYY-MM-DD"))?>
</select>
:notifications_date_format_help:
_(Time format)_:
: <select name="time" class="a">
<?=mk_option($notify['time'], "h:i A", _("12 hours"))?>
<?=mk_option($notify['time'], "H:i", _("24 hours"))?>
</select>
:notifications_time_format_help:
_(Display position)_:
: <select name="position" class="a">
<?=mk_option($notify['position'], "top-left", _("top-left"))?>
<?=mk_option($notify['position'], "top-right", _("top-right"))?>
<?=mk_option($notify['position'], "bottom-left", _("bottom-left"))?>
<?=mk_option($notify['position'], "bottom-right", _("bottom-right"))?>
<?=mk_option($notify['position'], "center", _("center"))?>
</select>
:notifications_display_position_help:
_(Store notifications to flash)_:
: <select name="path" class="a">
<?=mk_option($notify['path'], "/tmp/notifications", _("No"))?>
<?=mk_option($notify['path'], "/boot/config/plugins/dynamix/notifications", _("Yes"))?>
</select>
:notifications_store_flash_help:
_(System notifications)_:
: <select name="system" class="a" onchange="prepareSystem(this.selectedIndex)">
<?=mk_option($notify['system'], "", _("Disabled"))?>
<?=mk_option($notify['system'], "*/1 * * * *", _("Enabled"))?>
</select>
:notifications_system_help:
_(Unraid OS update notification)_:
: <select name="unraidos" class="a" onchange="prepareUnraid(this.value)">
<?=mk_option($notify['unraidos'], "", _("Never check"))?>
<?=mk_option($notify['unraidos'], "11 */6 * * *", _("Check four times a day"))?>
<?=mk_option($notify['unraidos'], "11 0,12 * * *", _("Check twice a day"))?>
<?=mk_option($notify['unraidos'], "11 0 * * *", _("Check once a day"))?>
<?=mk_option($notify['unraidos'], "11 0 * * 1", _("Check once a week"))?>
<?=mk_option($notify['unraidos'], "11 0 1 * *", _("Check once a month"))?>
</select>
:notifications_os_update_help:
_(Plugins update notification)_:
: <select name="version" class="a" onchange="preparePlugin(this.value)">
<?=mk_option($notify['version'], "", _("Never check"))?>
<?=mk_option($notify['version'], "10 */6 * * *", _("Check four times a day"))?>
<?=mk_option($notify['version'], "10 0,12 * * *", _("Check twice a day"))?>
<?=mk_option($notify['version'], "10 0 * * *", _("Check once a day"))?>
<?=mk_option($notify['version'], "10 0 * * 1", _("Check once a week"))?>
<?=mk_option($notify['version'], "10 0 1 * *", _("Check once a month"))?>
</select>
:notifications_plugins_update_help:
_(Docker update notification)_:
: <select name="docker_update" class="a" onchange="prepareDocker(this.value)">
<?=mk_option($notify['docker_update'], "", _("Never check"))?>
<?=mk_option($notify['docker_update'], "10 */6 * * *", _("Check four times a day"))?>
<?=mk_option($notify['docker_update'], "10 0,12 * * *", _("Check twice a day"))?>
<?=mk_option($notify['docker_update'], "10 0 * * *", _("Check once a day"))?>
<?=mk_option($notify['docker_update'], "10 0 * * 1", _("Check once a week"))?>
<?=mk_option($notify['docker_update'], "10 0 1 * *", _("Check once a month"))?>
</select>
:notifications_docker_update_help:
_(Language update notification)_:
: <select name="language_update" class="a" onchange="prepareLanguage(this.value)">
<?=mk_option($notify['language_update'], "", _("Never check"))?>
<?=mk_option($notify['language_update'], "10 */6 * * *", _("Check four times a day"))?>
<?=mk_option($notify['language_update'], "10 0,12 * * *", _("Check twice a day"))?>
<?=mk_option($notify['language_update'], "10 0 * * *", _("Check once a day"))?>
<?=mk_option($notify['language_update'], "10 0 * * 1", _("Check once a week"))?>
<?=mk_option($notify['language_update'], "10 0 1 * *", _("Check once a month"))?>
</select>
_(Array status notification)_:
: <select name="status" class="a" onchange="prepareReport(this.value)">
<?=mk_option($notify['status'], "", _("Never send"))?>
<?=mk_option($notify['status'], "20 * * * *", _("Send every hour"))?>
<?=mk_option($notify['status'], "20 */2 * * *", _("Send every two hours"))?>
<?=mk_option($notify['status'], "20 */6 * * *", _("Send four times a day"))?>
<?=mk_option($notify['status'], "20 */8 * * *", _("Send three times a day"))?>
<?=mk_option($notify['status'], "20 0,12 * * *", _("Send twice a day"))?>
<?=mk_option($notify['status'], "20 0 * * *", _("Send once a day"))?>
<?=mk_option($notify['status'], "20 0 * * 1", _("Send once a week"))?>
<?=mk_option($notify['status'], "20 0 1 * *", _("Send once a month"))?>
</select>
:notifications_array_status_help:
<span id="unraidTitle" class="unraid" style="display:none">&nbsp;</span>
: <span class="unraid" style="display:none"><span class="a">_(Unraid OS update)_</span>
<input type="checkbox" name="unraid1"<?=($notify['unraid'] & 1)==1 ? ' checked' : ''?>>_(Browser)_ &nbsp;
<input type="checkbox" name="unraid2"<?=($notify['unraid'] & 2)==2 ? ' checked' : ''?>>_(Email)_ &nbsp;
<input type="checkbox" name="unraid3"<?=($notify['unraid'] & 4)==4 ? ' checked' : ''?>>_(Agents)_ &nbsp;</span>
<span id="pluginTitle" class="plugin" style="display:none">&nbsp;</span>
: <span class="plugin" style="display:none"><span class="a">_(Plugins update)_</span>
<input type="checkbox" name="plugin1"<?=($notify['plugin'] & 1)==1 ? ' checked' : ''?>>_(Browser)_ &nbsp;
<input type="checkbox" name="plugin2"<?=($notify['plugin'] & 2)==2 ? ' checked' : ''?>>_(Email)_ &nbsp;
<input type="checkbox" name="plugin3"<?=($notify['plugin'] & 4)==4 ? ' checked' : ''?>>_(Agents)_ &nbsp;</span>
<span id="dockerTitle" class="docker" style="display:none">&nbsp;</span>
: <span class="docker" style="display:none"><span class="a">_(Docker update)_</span>
<input type="checkbox" name="docker_notify1"<?=($notify['docker_notify'] & 1)==1 ? ' checked' : ''?>>_(Browser)_ &nbsp;
<input type="checkbox" name="docker_notify2"<?=($notify['docker_notify'] & 2)==2 ? ' checked' : ''?>>_(Email)_ &nbsp;
<input type="checkbox" name="docker_notify3"<?=($notify['docker_notify'] & 4)==4 ? ' checked' : ''?>>_(Agents)_ &nbsp;</span>
<span id="languageTitle" class="language" style="display:none">&nbsp;</span>
: <span class="language" style="display:none"><span class="a">_(Language update)_</span>
<input type="checkbox" name="language_notify1"<?=($notify['language_notify'] & 1)==1 ? ' checked' : ''?>>_(Browser)_ &nbsp;
<input type="checkbox" name="language_notify2"<?=($notify['language_notify'] & 2)==2 ? ' checked' : ''?>>_(Email)_ &nbsp;
<input type="checkbox" name="language_notify3"<?=($notify['language_notify'] & 4)==4 ? ' checked' : ''?>>_(Agents)_ &nbsp;</span>
<span id="reportTitle" class="report" style="display:none">&nbsp;</span>
: <span class="report" style="display:none"><span class="a">_(Array status)_</span>
<input type="checkbox" name="report1"<?=($notify['report'] & 1)==1 ? ' checked' : ''?>>_(Browser)_ &nbsp;
<input type="checkbox" name="report2"<?=($notify['report'] & 2)==2 ? ' checked' : ''?>>_(Email)_ &nbsp;
<input type="checkbox" name="report3"<?=($notify['report'] & 4)==4 ? ' checked' : ''?>>_(Agents)_ &nbsp;</span>
:notifications_agent_selection_help:
_(Notification entity)_:
: <span class="a">_(Notices)_</span>
<input type="checkbox" class="checkbox" name="normal1"<?=($notify['normal'] & 1)==1 ? " checked $disabled" : $disabled?>>_(Browser)_ &nbsp;
<input type="checkbox" class="checkbox" name="normal2"<?=($notify['normal'] & 2)==2 ? " checked $disabled" : $disabled?>>_(Email)_ &nbsp;
<input type="checkbox" class="checkbox" name="normal3"<?=($notify['normal'] & 4)==4 ? " checked $disabled" : $disabled?>>_(Agents)_ &nbsp;
&nbsp;
: <span class="a">_(Warnings)_</span>
<input type="checkbox" class="checkbox" name="warning1"<?=($notify['warning'] & 1)==1 ? " checked $disabled" : $disabled?>>_(Browser)_ &nbsp;
<input type="checkbox" class="checkbox" name="warning2"<?=($notify['warning'] & 2)==2 ? " checked $disabled" : $disabled?>>_(Email)_ &nbsp;
<input type="checkbox" class="checkbox" name="warning3"<?=($notify['warning'] & 4)==4 ? " checked $disabled" : $disabled?>>_(Agents)_ &nbsp;
&nbsp;
: <span class="a">_(Alerts)_</span>
<input type="checkbox" class="checkbox" name="alert1"<?=($notify['alert'] & 1)==1 ? " checked $disabled" : $disabled?>>_(Browser)_ &nbsp;
<input type="checkbox" class="checkbox" name="alert2"<?=($notify['alert'] & 2)==2 ? " checked $disabled" : $disabled?>>_(Email)_ &nbsp;
<input type="checkbox" class="checkbox" name="alert3"<?=($notify['alert'] & 4)==4 ? " checked $disabled" : $disabled?>>_(Agents)_ &nbsp;
:notifications_classification_help:
<input type="submit" name="#default" value="_(Default)_">
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
@@ -0,0 +1,114 @@
Menu="UNRAID-OS"
Title="Archived Notifications"
Icon="icon-archive"
Tag="archive"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
* Copyright 2012, Andrew Hamer-Adams, http://www.pixeleyes.co.nz.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$files = count(glob("{$notify['path']}/archive/*.notify", GLOB_NOSORT));
$filters = mk_option(0,'',_('No filter')).mk_option(0,'alert',_('Alerts')).mk_option(0,'warning',_('Warnings')).mk_option(0,'normal',_('Notices'));
?>
<style>
select.filter{margin:0}
span.right{margin-top:-6px;font-size:1.3rem!important;padding:0!important}
i.red-text{font-size:1.6rem}
</style>
<script>
var rows = [];
var filter = "<?=unscript(_var($_GET,'filter'))?>";
var files = -1;
Array.prototype.remove = function() {
var val, a = arguments, L = a.length, ax;
while (L && this.length) {
val = a[--L];
while ((ax = this.indexOf(val)) !== -1) this.splice(ax, 1);
}
return this;
};
<?if (_var($display,'resize')):?>
function resize() {
$('#archive_list').height(Math.max(window.innerHeight-340,330));
$('#archive_table thead,#archive_table tbody').removeClass('fixed');
$('#archive_table thead tr th').each(function(){$(this).width($(this).width());});
$('#archive_table tbody tr td').each(function(){$(this).width($(this).width());});
$('#archive_table thead,#archive_table tbody').addClass('fixed');
}
<?endif;?>
function archiveList(init) {
clearTimeout(timers.archivelist);
timers.archive = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
$.get('/webGui/include/NotificationsArchive.php',{filter:filter},function(data) {
clearTimeout(timers.archive);
data = data.split('\0');
if (data[1]>0) $('#deleteAll').show(); else $('#deleteAll').hide();
if (files != data[1]) {
files = data[1];
$('#archive_list').html(data[0]);
<?if (_var($display,'resize')):?>
resize();
<?endif;?>
if (init) {
<?if (_var($display,'resize')):?>
$(window).bind('resize',function(){resize();});
<?endif;?>
$('#archive_table').tablesorter({headers:{5:{sorter:false}},textAttribute:'data'});
} else {
$('#archive_table').trigger('update');
}
$('#archive_list .tablesorter-childRow td').hide();
for (var i=0; i < rows.length; i++) $('#archive_list .tablesorter-childRow.row'+rows[i]+' td').show();
}
$('div.spinner.fixed').hide('slow');
timers.archivelist = setTimeout(archiveList,3000);
});
}
function askConfirmation() {
swal({
title:"_(Are you sure)_?",
text: filter=='' ? "_(This will delete all notification files)_!" : "_(This will delete the selected notification files)_!",
type:"warning",
html:true,
showCancelButton:true,
confirmButtonText:"_(Proceed)_",
cancelButtonText:"_(Cancel)_"
},
function(){$.post('/webGui/include/DeleteLogFile.php',{log:'*.notify',filter:filter},function(){$('#deleteAll').hide();archiveList();});});
}
function openClose(row) {
var extra = '#archive_list .tablesorter-childRow.row'+row+' td';
if ($(extra).is(":visible")) {
$(extra).hide();
rows.remove(row);
} else {
$(extra).show();
rows.push(row);
}
}
$(function(){
$('span.left').append("<span class='right'><select class='filter narrow' onchange='filter=this.value;archiveList()'><?=$filters?></select></span>");
$('select.filter').val(filter);
archiveList(true);
});
// Adjust the width of thead cells when window resizes
</script>
<table class="tablesorter left shift" id="archive_table">
<thead><tr><th>_(Time)_</th><th>_(Event)_</th><th>_(Subject)_</th><th>_(Description)_</th><th>_(Importance)_</th><th><a id="deleteAll" href="#" onclick="askConfirmation();return false" title="_(Delete all notifications)_" style="display:none"><i class="fa fa-trash-o red-text"></i></a></th></tr></thead>
<tbody id="archive_list"><tr><td colspan="6"></td></tr></tbody>
</table>
<input type="button" value="_(Done)_" onclick="done()">
+38
View File
@@ -0,0 +1,38 @@
Menu="Main:4"
Title="Unassigned Devices"
Tag="unlink"
Cond="(count($devs)>0)"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$tabX = '#tab'.($var['fsState']=='Stopped'||$pool_devices ? '4' : '3');
?>
<script>
<?if ($var['fsState']=='Started'):?>
$('<?=$tabX?>').bind({click:function() {$('i.toggle').show('slow');}});
<?endif;?>
</script>
<table class="disk_status wide">
<thead><tr><td>_(Device)_</td><td>_(Identification)_</td><td>_(Temp)_.</td><td>_(Reads)_</td><td>_(Writes)_</td><td>_(Errors)_</td><td>_(FS)_</td><td>_(Size)_</td><td>_(Used)_</td><td>_(Free)_</td></tr></thead>
<tbody id="open_devices">
<?
foreach ($devs as $dev):
echo "<tr><td colspan='11'>&nbsp;</td></tr>";
endforeach;
?>
</tbody>
</table>
:open_devices_help:
@@ -0,0 +1,4 @@
Menu="Settings:1"
Type="menu"
Title="System Settings"
Tag="cog"
+183
View File
@@ -0,0 +1,183 @@
Menu="WebGui"
Title="PHP Settings"
Icon="icon-template"
Tag="edit"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$log = "/var/log/phplog";
$ini = "/etc/php.d/errors-php.ini";
$conf = file_exists($ini) ? parse_ini_file($ini) : [];
if (!file_exists($log)) touch($log);
?>
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.ui.css")?>">
<link type="text/css" rel="stylesheet" href="<?autov("/plugins/dynamix.docker.manager/styles/style-$theme.css")?>">
<style>
div#templateWindow,div#dialogWindow{display:none}
span.dim{opacity:0.2}
#screenlog{margin-left:0}
</style>
<div markdown="1" style="width:43%;margin-bottom:40px;padding:5px 15px;border:solid 1px">
:php_settings_plug:
This utility is used for development purposes only and allows Plugin Authors to verify their PHP code by enabling different levels of PHP error reporting.
By default error logging is minimum and any errors are shown on screen. Changing the **Error reporting level** will capture the selected level of errors
into a LOG file, which can be opened in a separate window to monitor in real-time the events when visiting various GUI pages or executing background
processes on the server.
The LOG file can quickly grow large when multiple errors exists, it is advised to use it only during development and use the default setting
under normal running conditions.
:end
</div>
<form markdown="1" name="php_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="preset(this)">
<input type="hidden" name="#cleanup" value="1">
<input type="hidden" name="#file" value="<?=$ini?>">
<input type="hidden" name="error_log" value="<?=$log?>">
<input type="hidden" name="display_startup_errors" value="0">
<input type="hidden" name="display_errors" value="<?=_var($conf,'display_errors',0)?>">
<input type="hidden" name="log_errors" value="1">
_(Error reporting level)_:
: <select name="error_reporting" onchange="toggleScreen(this.selectedIndex)">
<?=mk_option(_var($conf,'error_reporting'), "", "_(Default)_");?>
<?=mk_option(_var($conf,'error_reporting'), "32767", "_(All Categories)_");?>
<?=mk_option(_var($conf,'error_reporting'), "1", "_(Errors Only)_");?>
<?=mk_option(_var($conf,'error_reporting'), "2", "_(Warnings Only)_");?>
<?=mk_option(_var($conf,'error_reporting'), "8", "_(Notices Only)_");?>
<?=mk_option(_var($conf,'error_reporting'), "8192", "_(Deprecated Only)_");?>
</select>
&nbsp;
: <input type="checkbox" id="screenlog" onclick="screenLog()" <?=_var($conf,'display_errors',0)?'checked':''?> disabled><span id="screentext" class="dim">_(Show errors on screen)_</span>
<input type="button" value="_(PHP Info)_" onclick="PHPinfo()"><input type="button" id="clearlog" value="_(Clear Log)_" onclick="clearLog()"<?=filesize($log)>0?'':' disabled'?>><input type="button" id="viewlog" value="_(View Log)_" onclick="viewLog()" disabled>_(LOG size)_:&nbsp;<span id="logsize"></span>
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<div id="dialogWindow"></div>
<div markdown="1" id="templateWindow">
<!--!
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
<style>
table{box-shadow:1px 2px 3px rgba(0,0,0,0.2);width:90%}
.center{text-align:center;color:#f2f2f2!important;background-color:#1c1b1b}
.center table{margin:1em auto;text-align:left}
.center th{text-align:center!important}
td,th{border:1px solid #505153;vertical-align:baseline;padding:4px 5px!important;color:#f2f2f2}
th{position:sticky;top:0}
img{float:right;border:0}
hr{width:90%;background-color:#505153;border:0;height:1px}
h1{font-size:150%}
h2{font-size:125%}
h2 a{color:#f2f2f2!important}
.p{text-align:left}
.e{background-color:#404A77;width:300px}
.h{background-color:#4F5B93}
.v{background-color:#333;max-width:300px;overflow-x:auto;word-wrap:break-word}
.v i{color:#999}
.h td,td.e,th{border-color:#606A90}
</style>
<body>
<?
ob_start();
phpinfo();
echo preg_replace('/^<!DOCTYPE html .*<body>/s','',ob_get_clean());
?>
!-->
</div>
<script>
String.prototype.build = function(){return this.replace(/\n(<!--!|!-->)\n/g,'');}
var box = null;
function screenLog() {
$('input[name="display_errors"]').val($('#screenlog').prop('checked')?1:0);
}
function viewLog() {
openTerminal('log','PHP Error Log','phplog');
}
function clearLog() {
$.post('/webGui/include/PHPsettings.php',{cmd:'clear'},function(){
swal({title:"_(PHP Log File)_",text:"_(Log file cleared)_",type:'success',html:true,confirmButtonText:"_(Ok)_"},function(){
if (tty_window==null) viewLog();
tty_window.close();
$('#clearlog').prop('disabled',true);
});
});
}
function logSize() {
$.post('/webGui/include/PHPsettings.php',{cmd:'logsize'},function(size){
$('#logsize').text(size);
if (size.split(' ')[0]!=0) {$('#clearlog').prop('disabled',false);$('#viewlog').prop('disabled',false);}
setTimeout(logSize,3000);
});
}
function PHPinfo() {
box = $("#dialogWindow");
box.html($("#templateWindow").html().build());
box.dialog({
title: "_(PHP Information)_",
resizable: false,
height: Math.min(window.innerHeight-80,800),
width: Math.min(window.innerWidth,1200),
modal: true,
show: {effect:'fade', duration:250},
hide: {effect:'fade', duration:250},
buttons: {
"_(Done)_": function(){
box.dialog('close');
}
}
});
$('.ui-dialog-titlebar-close').css({'display':'none'});
$('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
$('.ui-button-text').css({'padding':'0 5px'});
}
function preset(form) {
// reset to default settings
if (form.error_reporting.selectedIndex==0) {
form.error_log.value = "";
form.display_startup_errors.value = "";
form.display_errors.value = "";
form.log_errors.value = "";
}
$.cookie('reload_php',1);
}
function toggleScreen(index) {
if (index > 0) {
$('#screenlog').prop('disabled',false);
$('#screentext').removeClass('dim');
} else {
$('#screenlog').prop('disabled',true);
$('#screentext').addClass('dim');
}
}
$(function(){
logSize();
if (document.php_settings.error_reporting.selectedIndex > 0) {
$('#viewlog').prop('disabled',false);
$('#screenlog').prop('disabled',false);
$('#screentext').removeClass('dim');
}
if ($.cookie('reload_php')==1) {
$.removeCookie('reload_php');
$.post('/webGui/include/PHPsettings.php',{cmd:'reload'});
}
});
</script>
+66
View File
@@ -0,0 +1,66 @@
Menu="WebGui"
Title="Page Map"
Icon="icon-pagemap"
Tag="map-o"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?if (_var($display,'resize')):?>
<script>
function resize() {
$('div.up').height(Math.max(window.innerHeight-320,330));
}
$(function() {
resize();
$(window).bind('resize',function(){resize();});
});
</script>
<?endif;?>
<?
function show_map($menu, $level) {
$pages = find_pages( $menu);
if (empty($pages))
return;
echo "<ul>";
foreach ($pages as $page) {
$link = "<a href='/{$page['name']}'>{$page['name']}</a>";
$title = _($page['Title'] ?? '');
$type = $page['Type'] ?? '';
if ($type == "menu") {
$link = "($link)";
} elseif ($type == "xmenu") {
$link = "[$link]";
}
echo "$level $link",($title ? " - $title" : ""),"<br>";
show_map($page['name'], $level+1);
}
echo "</ul>";
}
$uri = ['dashboard','main','shares','users','settings','plugins','docker','vms'];
foreach($uri as $more) {
$text = "$docroot/languages/$locale/$more.txt";
if (file_exists($text)) {
// additional translations
$store = "$docroot/languages/$locale/$more.dot";
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
$language = array_merge($language,unserialize(file_get_contents($store)));
}
}
echo "<div class='up'>";
show_map("Tasks", 1);
show_map("Buttons", 1);
echo "</div>";
?>
<input type="button" value="_(Done)_" onclick="done()">
+229
View File
@@ -0,0 +1,229 @@
Menu="Scheduler:1"
Title="Parity Check"
Tag="calendar"
---
<?PHP
/* Copyright 2012-2023, Bergware International.
* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
if (_var($disks['parity'],'status')=='DISK_NP_DSBL' && _var($disks['parity2'],'status')=='DISK_NP_DSBL') {
echo "<p class='notice'>"._('No Parity disk present')."!</p>";
}
$width = [166,300];
$mode = ['Disabled','Daily','Weekly','Monthly','Yearly','Custom'];
$days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
$months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
$memory = '/tmp/memory.tmp';
if (file_exists($memory)) {
parse_str(file_get_contents($memory), $parity);
if (empty($parity['hour'])) $parity['hour'] = "";
if (empty($parity['day'])) $parity['day'] = "";
if (empty($parity['dotm'])) $parity['dotm'] = "";
if (empty($parity['month'])) $parity['month'] = "";
if (empty($parity['write'])) $parity['write'] = "NOCORRECT";
}
if ($parity['mode']<2) $parity['cumulative'] = '';
if ($parity['mode']==2) $parity['frequency'] = '1';
?>
<script>
<?if ($parity['mode']==5):?>
$(function() {
$("#s1").dropdownchecklist({emptyText:"_(Every day)_", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
$("#s2").dropdownchecklist({emptyText:"_(Every month)_", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
});
// Simulate a single input field
function prepareParity(form) {
var days = '';
for (var i=0,item; item=form.day.options[i]; i++) {
if (item.selected) {
if (days.length) days += ',';
days += item.value;
item.selected = false;
}
}
item = form.day.options[0];
item.value = days || '*';
item.selected = true;
var months = '';
for (var i=0,item; item=form.month.options[i]; i++) {
if (item.selected) {
if (months.length) months += ',';
months += item.value;
item.selected = false;
}
}
item = form.month.options[0];
item.value = months || '*';
item.selected = true;
}
<?else:?>
function prepareParity(form) {
// do nothing
}
<?endif;?>
$(function() {
<?if (file_exists($memory)):?>
setTimeout(function(){$('input[value="_(Apply)_"]').removeAttr('disabled');},0);
$('input[value="_(Done)_"]').val("_(Reset)_").prop('onclick',null).click(function(){refresh($(this).parentsUntil('form').parent().offset().top)});
<?unlink($memory);?>
<?endif;?>
presetParity(document.parity_settings);
});
function presetParity(form) {
var mode = form.mode.value;
form.day.disabled = mode!=2 && mode!=5;
form.dotm.disabled = mode<3;
form.hour.disabled = mode==0;
form.month.disabled = mode<4;
form.write.disabled = mode==0;
}
function showCumulative(val,pace) {
if (val=='') $('#cumulative').hide(pace); else $('#cumulative').show(pace);
}
$(function(){
showCumulative($('select[name="cumulative"]').val());
});
</script>
<form markdown="1" name="parity_settings" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareParity(this)">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg"/>
<input type="hidden" name="#section" value="parity"/>
<input type="hidden" name="#include" value="/webGui/include/update.parity.php"/>
_(Scheduled parity check)_:
: <select name="mode" onchange="submit()">
<?for ($m=0; $m<count($mode); $m++):?>
<?=mk_option($parity['mode'], strval($m), _($mode[$m]))?>
<?endfor;?>
</select>
:parity_check_scheduled_help:
_(Day of the week)_:
<?if ($parity['mode']==2):?>
: <select name="day">
<?for ($d=0; $d<count($days); $d++):?>
<?=mk_option($parity['day'], strval($d), ucfirst(_($days[$d],0)))?>
<?endfor;?>
<?elseif ($parity['mode']==5):?>
: <select id="s1" name="day" multiple="multiple" style="display:none">
<?for ($d=0; $d<count($days); $d++):?>
<?=mk_option_check($parity['day'], strval($d), ucfirst(_($days[$d],0)))?>
<?endfor;?>
<?else:?>
: <select name="day">
<?=mk_option($parity['day'], "*", "--------")?>
<?endif;?>
</select>
:parity_day_of_the_week_help:
<?if ($parity['mode']<5):?>
_(Day of the month)_:
<?else:?>
_(Week of the month)_:
<?endif;?>
: <select name="dotm">
<?if ($parity['mode']>=3):?>
<?if ($parity['mode']==5):?>
<?=mk_option($parity['dotm'], "*", _("Every week"))?>
<?=mk_option($parity['dotm'], "W1", _("First week"))?>
<?=mk_option($parity['dotm'], "W2", _("Second week"))?>
<?=mk_option($parity['dotm'], "W3", _("Third week"))?>
<?=mk_option($parity['dotm'], "W4", _("Fourth week"))?>
<?=mk_option($parity['dotm'], "WL", _("Last week"))?>
<?else:?>
<?=mk_option($parity['dotm'], "1", _("First day"))?>
<?=mk_option($parity['dotm'], "28-31", _("Last day"))?>
<?for ($d=2; $d<=31; $d++):?>
<?=mk_option($parity['dotm'], strval($d), sprintf("%02d", $d))?>
<?endfor;?>
<?endif;?>
<?else:?>
<?=mk_option($parity['dotm'], "*", "--------")?>
<?endif;?>
</select>
:parity_week_of_the_month_help:
_(Time of the day)_:
: <select name="hour">
<?if ($parity['mode']>0):?>
<?for ($h=0; $h<24; $h++):?>
<?=mk_option($parity['hour'], sprintf("0 %d", $h), sprintf("%02d:00", $h))?>
<?=mk_option($parity['hour'], sprintf("30 %d",$h), sprintf("%02d:30", $h))?>
<?endfor;?>
<?else:?>
<?=mk_option($parity['hour'], "*", "--------")?>
<?endif;?>
</select>
:parity_time_of_the_day_help:
_(Month of the year)_:
<?if ($parity['mode']>=4):?>
<?if ($parity['mode']==5):?>
: <select id="s2" name="month" multiple="multiple" style="display:none">
<?for ($m=0; $m<count($months); $m++):?>
<?=mk_option_check($parity['month'], strval($m+1), ucfirst(_($months[$m],0)))?>
<?endfor;?>
<?else:?>
: <select name="month">
<?for ($m=0; $m<count($months); $m++):?>
<?=mk_option($parity['month'], strval($m+1), ucfirst(_($months[$m],0)))?>
<?endfor;?>
<?endif;?>
<?else:?>
: <select name="month">
<?=mk_option($parity['month'], "*", "--------")?>
<?endif;?>
</select>
:parity_month_of_the_year_help:
_(Write corrections to parity disk)_:
: <select name="write">
<?=mk_option($parity['write'], "NOCORRECT", _("No"))?>
<?=mk_option($parity['write'], "", _("Yes"))?>
</select>
:parity_write_corrections_help:
_(Cumulative parity check)_:
: <select name="cumulative" onchange="showCumulative(this.value,'slow')" <?=$parity['mode']>1?'':'disabled'?>>
<?=mk_option(_var($parity,'cumulative'), "", _("No"))?>
<?=mk_option(_var($parity,'cumulative'), "1", _("Yes"))?>
</select>
:parity_cumulative_check_help:
<div markdown="1" id="cumulative" style="display:none">
_(Accumulation frequency)_:
: <select name="frequency">
<?=mk_option(_var($parity,'frequency'), "1", _("Daily"))?>
<?=mk_option(_var($parity,'frequency'), "7", _("Weekly"),$parity['mode']==2 ? 'disabled' : '')?>
</select>
:parity_accumulation_frequency_help:
_(Accumulation duration)_:
: <select name="duration">
<?for ($h=1; $h<24; $h++):?>
<?=mk_option(_var($parity,'duration'), $h, $h.' '._('hour'.($h==1?'':'s')))?>
<?endfor;?>
</select>
:parity_accumulation_duration_help:
</div>
&nbsp;
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()"></td>
</form>
+32
View File
@@ -0,0 +1,32 @@
Menu="UNRAID-OS"
Title="Processes"
Icon="icon-processes"
Tag="cogs"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?if (_var($display,'resize')):?>
<script>
function resize() {
$('pre.up').height(Math.max(window.innerHeight-320,330));
}
$(function() {
resize();
$(window).bind('resize',function(){resize();});
});
</script>
<?endif;?>
<?
echo "<pre class='up'>",shell_exec('ps -aux'),"</pre>";
?>
<input type="button" value="_(Done)_" onclick="done()">
+5
View File
@@ -0,0 +1,5 @@
**Dynamix webGui**
The *Dynamix* webGui is the latest iteration of the Unraid OS System
Management Utility. Built upon *Simple Features*, it provides real-time
screen updates, tabbed viewing and many more enhancements.
+102
View File
@@ -0,0 +1,102 @@
Menu="NetworkSettings"
Title="Routing Table"
Tag="icon-share"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
unset($list,$other);
exec("ls /sys/class/net|grep -P '^br[0-9]'",$list);
exec("ls /sys/class/net|grep -P '^(bond|eth)[0-9]'",$other);
foreach ($other as $port) {
if (substr($port,0,4)=='bond') {
$br = str_replace('bond','br',$port);
if (!in_array($br,$list)) $list[] = $port;
} else {
$br = str_replace('eth','br',$port);
$bond = str_replace('eth','bond',$port);
if (!in_array($br,$list) && !in_array($bond,$list)) $list[] = $port;
}
}
?>
<style>
input.fixed{width:200px;}
<?if ($themes1):?>
span.status.vhshift{margin-right:-10px!important}
<?endif;?>
</style>
<script>
function deleteRoute(gateway,route,metric) {
swal({title:"Delete route?",text:route+" by gateway "+gateway,type:"warning",html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){
$.post('/webGui/include/RoutingTable.php',{gateway:gateway,route:route,metric:metric,task:'delete'},function(){resetTable();});
});
}
function routeTable() {
$.post('/webGui/include/RoutingTable.php',{task:'update'},function(data){
if (data) $('#route_list').html(data);
timers.routeTable = setTimeout(routeTable,10000);
});
}
function resetTable() {
document.add_routes.route.value = '';
document.add_routes.gateway.value = '';
document.add_routes.metric.value = '';
clearTimeout(timers.routeTable);
routeTable();
}
<?if (!$tabbed):?>
function toggleTable() {
var tag = '#tag_table';
var view = '#route_table';
if ($(view).is(':visible')) {
$(tag).removeClass('fa-chevron-up').addClass('fa-chevron-down');
$.cookie(view,'hide',{expires:3650});
} else {
$(tag).removeClass('fa-chevron-down').addClass('fa-chevron-up');
$.removeCookie(view);
}
$(view).toggle('slow');
}
$(function(){
$('div.title').last().find('span.left').append("<span class='status vhshift'><i id='tag_table' class='fa fa-fw fa-chevron-up' style='cursor:pointer' onclick='toggleTable()'></i></span>");
if (!$.cookie('#route_table')) $('#route_table').show(); else $('#tag_table').removeClass('fa-chevron-up').addClass('fa-chevron-down');
routeTable();
});
<?else:?>
$(function(){
$('#route_table').show();
routeTable();
});
<?endif;?>
</script>
<div markdown="1" id="route_table" style="display:none">
<table class="share_status">
<thead><tr><td>_(Protocol)_</td><td>_(Route)_</td><td>_(Gateway)_</td><td>_(Metric)_</td><td style="width:8%;text-align:center">_(Delete)_</td></tr></thead>
<tbody id="route_list"></tbody>
</table>
<div class="shade-<?=$display['theme']?>" style="margin-top:12px;padding:12px 4px;">
<form markdown="1" name="add_routes" method="POST" action="/webGui/include/RoutingTable.php" target="progressFrame" onsubmit="setTimeout(resetTable,500)">
_(Enter route + gateway + metric)_:
: <input type="text" name="route" maxlength="39" value="" class="fixed" placeholder="_(IPv4/nn or IPv6/nn route)_" required>
<input type="text" name="gateway" class="fixed" value="" list="device" placeholder="_(gateway name or address)_" required>
<datalist id="device"><?foreach ($list as $port):?><?echo "<option value='$port'>"?><?endforeach;?></datalist>
<input type="text" name="metric" min="1" max="9999" value="" class="trim" placeholder="1"><i class="fa fa-sort-numeric-asc"></i> *_(optional metric (lowest is preferred))_*
:eth_routing_table_help:
&nbsp;
: <input type="submit" name="task" value="_(Add Route)_"><input type="button" value="_(Done)_" class="lock" onclick="done()">
</form>
</div>
</div>
+4
View File
@@ -0,0 +1,4 @@
Menu="NetworkServices:3"
Type="xmenu"
Title="SMB"
Icon="icon-windows"
@@ -0,0 +1,52 @@
Menu="SMB:3"
Title="Active Directory Settings"
Tag="list-ul"
Cond="($var['shareSMBEnabled']=='ads')"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<form markdown="1" name="JoinOps" method="POST" action="/update.htm" target="progressFrame">
_(AD join status)_:
: <?=$var['joinStatus'];?>&nbsp;
_(AD domain name)_ (FQDN):
: <input type="text" name="DOMAIN" maxlength="80" value="<?=htmlspecialchars($var['DOMAIN'])?>">
_(AD short domain name)_:
: <input type="text" name="DOMAIN_SHORT" maxlength="40" value="<?=htmlspecialchars($var['DOMAIN_SHORT'])?>">
_(AD account login)_:
: <input type="text" name="DOMAIN_LOGIN" maxlength="40" value="<?=htmlspecialchars($var['DOMAIN_LOGIN'])?>">
_(AD account password)_:
: <input type="password" name="DOMAIN_PASSWD" maxlength="40" value="<?=htmlspecialchars($var['DOMAIN_PASSWD'])?>">
&nbsp;
: <?if ($var['joinStatus']=="Joined"):?>
<input type="submit" name="cmdJoinDomain" value="_(Join)_" disabled><input type="submit" name="cmdLeaveDomain" value="_(Leave)_">
<?else:?>
<input type="submit" name="cmdJoinDomain" value="_(Join)_"><input type="submit" name="cmdLeaveDomain" value="_(Leave)_" disabled>
<?endif;?>
</form>
<br>
<form markdown="1" name="shareOwnership" method="POST" action="/update.htm" target="progressFrame">
_(AD initial owner)_:
: <input type="text" name="shareInitialOwner" maxlength="40" value="<?=htmlspecialchars($var['shareInitialOwner'])?>">
_(AD initial group)_:
: <input type="text" name="shareInitialGroup" maxlength="40" value="<?=htmlspecialchars($var['shareInitialGroup'])?>">
&nbsp;
: <input type="submit" name="changeShare" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
+43
View File
@@ -0,0 +1,43 @@
Menu="SMB:2"
Title="SMB Extras"
Cond="($var['shareSMBEnabled']!='no')"
Tag="share-alt-square"
---
<?PHP
/* Copyright 2020, Lime Technology
* Copyright 2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
:smb_extra_conf_help:
<?
$file = "/boot/config/smb-extra.conf";
$text = @file_get_contents($file) ?: '';
$text = preg_replace(["/\r\n/","/\r/"],"\n",$text);
?>
<script>
$(function(){
$('form').find('textarea').on('input change',function(){
$(this).prop('rows',($(this).val().match(/\n/g)||[]).length+1);
});
});
</script>
<form markdown="1" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#include" value="/webGui/include/update.file.php">
<input type="hidden" name="#file" value="<?=$file;?>">
_(Samba extra configuration)_:
: <textarea spellcheck="false" cols="80" rows="<?=substr_count($text,"\n")+1?>" maxlength="2048" name="text" style="resize:none;font-family:bitstream;width:65.5%" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>><?=htmlspecialchars($text)?></textarea>
&nbsp;
: <input type="submit" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()"><?if ($var['fsState']=="Started"):?>*_(Array must be **Stopped** to change)_*<?endif;?>
:smb_extra_button_help:
</form>
+36
View File
@@ -0,0 +1,36 @@
Menu="SMB:2"
Title="Workgroup Settings"
Tag="sitemap"
Cond="($var['shareSMBEnabled']=='yes')"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<form markdown="1" name="WorkGroup" method="POST" action="/update.htm" target="progressFrame">
_(Workgroup)_:
: <input type="text" name="WORKGROUP" maxlength="40" value="<?=htmlspecialchars($var['WORKGROUP'])?>" class="narrow" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
:smb_workgroup_help:
<?if ($var['USE_NETBIOS']=="yes"):?>
_(Local master)_:
: <select name="localMaster" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['localMaster'], "no", _('No'))?>
<?=mk_option($var['localMaster'], "yes", _('Yes'))?>
</select>
:smb_local_master_help:
<?endif?>
&nbsp;
: <input type="submit" name="changeShare" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()"><?if ($var['fsState']=="Started"):?>*_(Array must be **Stopped** to change)_*<?endif;?>
</form>
+87
View File
@@ -0,0 +1,87 @@
Menu="SMB:1"
Title="SMB Settings"
Tag="windows"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<form markdown="1" name="SMBEnable" method="POST" action="/update.htm" target="progressFrame">
_(Enable SMB)_:
: <select name="shareSMBEnabled" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['shareSMBEnabled'], "no", _('No'))?>
<?=mk_option($var['shareSMBEnabled'], "yes", _('Yes').' ('._('Workgroup').')')?>
<?=mk_option($var['shareSMBEnabled'], "ads", _('Yes').' ('._('Active Directory').')')?>
</select>
:smb_enable_help:
_(Hide "dot" files)_:
: <select name="hideDotFiles" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['hideDotFiles'], "no", _('No'))?>
<?=mk_option($var['hideDotFiles'], "yes", _('Yes'))?>
</select>
:smb_hide_files_help:
_(Enable SMB Multi Channel)_:
: <select name="serverMultiChannel" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['serverMultiChannel'], "no", _('No'))?>
<?=mk_option($var['serverMultiChannel'], "yes", _('Yes'))?>
</select>
:smb_multi_channel_help:
_(Enhanced macOS interoperability)_:
: <select name="enableFruit" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['enableFruit'], "no", _('No'))?>
<?=mk_option($var['enableFruit'], "yes", _('Yes'))?>
</select>
:smb_enhanced_macos_help:
_(Enable NetBIOS)_:
: <select name="USE_NETBIOS" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['USE_NETBIOS'], "no", _('No'))?>
<?=mk_option($var['USE_NETBIOS'], "yes", _('Yes'))?>
</select>
:smb_enable_netbios_help:
_(Enable WSD)_:
: <select name="USE_WSD" onchange="checkWSDSettings()" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
<?=mk_option($var['USE_WSD'], "no", _('No'))?>
<?=mk_option($var['USE_WSD'], "yes", _('Yes'))?>
</select>
:smb_enable_wsd_help:
_(WSD options [experimental])_:
: <input type="text" name="WSD2_OPT" maxlength="80" class="narrow" value="<?=htmlspecialchars($var['WSD2_OPT'])?>" <?if ($var['fsState']=="Started"):?>disabled<?endif;?>>
:smb_wsd_options_help:
&nbsp;
: <input type="submit" name="changeShare" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()"><?if ($var['fsState']=="Started"):?>*_(Array must be **Stopped** to change)_*<?endif;?>
</form>
<script>
function checkWSDSettings() {
form=document.SMBEnable;
if (form.USE_WSD.value=="yes") {
form.WSD2_OPT.disabled=false;
} else {
form.WSD2_OPT.disabled=true;
}
}
$(checkWSDSettings);
</script>
+4
View File
@@ -0,0 +1,4 @@
Menu="UserPreferences"
Type="xmenu"
Title="Scheduler"
Icon="icon-scheduler"
+142
View File
@@ -0,0 +1,142 @@
Menu="Disk Share"
Title="NFS Security Settings"
Tag="linux"
Cond="(($var['shareNFSEnabled']!='no') && (isset($name)?array_key_exists($name,$sec_nfs):0))"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$width = [123,300];
?>
:nfs_security_help:
<div class="clone1">
<span class="clone">_(Read settings from)_</span><i class="fa fa-arrow-left fa-fw"></i>
<span class="wrap"><select name="readnfs" class="clone" onchange="toggleButton('readnfs',false)">
<option disabled selected>_(select)_...</option>
<?
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name) echo mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name) echo mk_option("", $list['name'], compress($list['name']));
}
?>
</select></span><input type="button" id="readnfs" value="_(Read)_" class="clone" onclick="readNFS()" disabled>
</div>
<div class="clone2">
<span class="clone">_(Write settings to)_</span><i class="fa fa-arrow-right fa-fw"></i>
<span class="wrap"><select id="nfs1" name="writenfs" multiple="multiple" style="display:none" onchange="toggleButton('writenfs',this.id)">
<?
$rows = [];
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name) $rows[] = mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name) $rows[] = mk_option("", $list['name'], compress($list['name']));
}
if ($rows) echo "<option>("._('All').")</option>";
foreach ($rows as $row) echo $row;
?>
</select></span><input type="button" id="writenfs" value="_(Write)_" class="clone" onclick="writeNFS()" disabled>
</div>
<form markdown="1" name="nfs_edit" method="POST" action="/update.htm" target="progressFrame" onchange="toggleButton('writenfs',true);$('#nfs1').dropdownchecklist('disable')">
<input type="hidden" name="shareName" value="<?=htmlspecialchars($name)?>">
_(Share name)_:
: <?=htmlspecialchars($name)?>
_(Export)_:
: <select name="shareExportNFS">
<?=mk_option($sec_nfs[$name]['export'], "-", _('No'));?>
<?=mk_option($sec_nfs[$name]['export'], "e", _('Yes'));?>
</select>
_(Security)_:
: <select name="shareSecurityNFS">
<?=mk_option($sec_nfs[$name]['security'], "public", _('Public'));?>
<?=mk_option($sec_nfs[$name]['security'], "secure", _('Secure'));?>
<?=mk_option($sec_nfs[$name]['security'], "private", _('Private'));?>
</select>
&nbsp;
: <input type="submit" name="changeShareSecurityNFS" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?if ($sec_nfs[$name]['security']=='private'):?>
<form markdown="1" method="POST" name="otherForm" action="/update.htm" target="progressFrame">
<input type="hidden" name="shareName" value="<?=htmlspecialchars($name)?>">
_(Rule)_:
: <input type="text" name="shareHostListNFS" maxlength="256" value="<?=htmlspecialchars($sec_nfs[$name]['hostList'])?>">
&nbsp;
: <input type="submit" name="changeShareAccessNFS" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?endif;?>
<script>
$(function() {
initDropdownNFS(false);
if ($.cookie('hostList')!=null) {
var host = $('input[name="shareHostListNFS"]');
host.val($.cookie('hostList'));
setTimeout(function(){host.trigger('change');},100);
$.removeCookie('hostList');
}
<?if ($tabbed):?>
<?$path=='Shares/Share' ? $t=2 : $t=1;?>
$('#tab<?=$t?>').bind({click:function(){initDropdownNFS(true);}});
<?endif;?>
});
function initDropdownNFS(reset) {
if (reset) {
$('#nfs1').dropdownchecklist('destroy');
}
$("#nfs1").dropdownchecklist({firstItemChecksAll:true, emptyText:"_(select)_...", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
}
function readNFS() {
var form = document.nfs_edit;
var name = $('select[name="readnfs"]').val();
$.get('/webGui/include/ProtocolData.php',{protocol:'nfs',name:name},function(json) {
var data = $.parseJSON(json);
form.shareExportNFS.value = data.export;
form.shareSecurityNFS.value = data.security;
if (data.hostList != '') $.cookie('hostList',data.hostList);
$(form).find('select').trigger('change');
});
}
function writeNFS(data,n,i) {
if (data) {
if (n<i) {
$.post('/update.htm',data[n], function(){setTimeout(function(){writeNFS(data,++n,i);},3000);});
} else {
toggleButton('writenfs',false);
$('div.spinner.fixed').hide();
}
} else {
var data = [], i = 0;
$('select#nfs1 option').map(function(i) {
if ($(this).prop('selected')==true && $(this).val()!='(_(All)_)') {
data[i] = {};
data[i]['shareName'] = $(this).val();
data[i]['shareExportNFS'] = '<?=addslashes(htmlspecialchars($sec_nfs[$name]['export']))?>';
data[i]['shareSecurityNFS'] = '<?=addslashes(htmlspecialchars($sec_nfs[$name]['security']))?>';
data[i]['changeShareSecurityNFS'] = 'Apply';
i++;
}
});
toggleButton('writenfs',true);
$('div.spinner.fixed').show('slow');
writeNFS(data,0,i);
}
}
</script>
+318
View File
@@ -0,0 +1,318 @@
Menu="Disk Share Flash"
Title="SMB Security Settings"
Tag="windows"
Cond="(($var['shareSMBEnabled']!='no') && (isset($name)?array_key_exists($name,$sec):0))"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
require_once "$docroot/webGui/include/InputSecurity.php";
$width = [123,300];
?>
:smb_security_help:
<div class="clone1">
<span class="clone">_(Read settings from)_</span><i class="fa fa-arrow-left fa-fw"></i>
<span class="wrap"><select name="readsmb" class="clone" onchange="toggleButton('readsmb',false)">
<option disabled selected>_(select)_...</option>
<?
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name) echo mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name) echo mk_option("", $list['name'], compress($list['name']));
}
?>
</select></span><input type="button" id="readsmb" value="_(Read)_" class="clone" onclick="readSMB()" disabled>
</div>
<div class="clone2">
<span class="clone">_(Write settings to)_</span><i class="fa fa-arrow-right fa-fw"></i>
<span class="wrap"><select id="smb1" name="writesmb" multiple="multiple" style="display:none" onchange="toggleButton('writesmb',this.id)">
<?
$rows = [];
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name) $rows[] = mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name) $rows[] = mk_option("", $list['name'], compress($list['name']));
}
if ($rows) echo "<option>("._('All').")</option>";
foreach ($rows as $row) echo $row;
?>
</select></span><input type="button" id="writesmb" value="_(Write)_" class="clone" onclick="writeSMB()" disabled>
</div>
<form markdown="1" name="smb_edit" method="POST" action="/update.htm" target="progressFrame" onchange="toggleButton('writesmb',true);$('#smb1').dropdownchecklist('disable')">
<input type="hidden" name="shareName" value="<?=htmlspecialchars($name)?>">
_(Share name)_:
: <?=htmlspecialchars($name)?>
<?if (($name=='flash')||($var['enableFruit']!='yes')):?>
_(Export)_:
: <select name="shareExport">
<?=mk_option($sec[$name]['export'], "-", _('No'))?>
<?=mk_option($sec[$name]['export'], "e", _('Yes'))?>
<?=mk_option($sec[$name]['export'], "eh", _('Yes (hidden)'))?>
</select>
:smb_export_help:
<input type="hidden" name="shareVolsizelimit" value="">
<?else:?>
_(Export)_:
: <select name="shareExport" onchange="checkShareSettingsSMB(this.form)">
<?=mk_option($sec[$name]['export'], "-", _('No'))?>
<?=mk_option($sec[$name]['export'], "e", _('Yes'))?>
<?=mk_option($sec[$name]['export'], "eh", _('Yes (hidden)'))?>
<?=mk_option($sec[$name]['export'], "et", _('Yes/Time Machine'))?>
<?=mk_option($sec[$name]['export'], "eth", _('Yes/Time Machine (hidden)'))?>
</select>
:smb_export_help:
_(Time Machine volume size limit)_:
: <input type="text" name="shareVolsizelimit" maxlen="20" value="<?=$sec[$name]['volsizelimit']?>"> MB
:smb_time_machine_volume_help:
<?endif;?>
<?if ($name!='flash'):?>
_(Case-sensitive names)_:
: <select name="shareCaseSensitive">
<?=mk_option($sec[$name]['caseSensitive'], "auto", _("Auto"))?>
<?=mk_option($sec[$name]['caseSensitive'], "yes", _("Yes"))?>
<?=mk_option($sec[$name]['caseSensitive'], "forced", _("Force lower"))?>
</select>
:smb_case_sensitive_names_help:
<?endif;?>
_(Security)_:
: <select name="shareSecurity">
<?=mk_option($sec[$name]['security'], "public", _('Public'))?>
<?=mk_option($sec[$name]['security'], "secure", _('Secure'))?>
<?=mk_option($sec[$name]['security'], "private", _('Private'))?>
</select>
:smb_security_modes_help:
&nbsp;
: <input type="submit" name="changeShareSecurity" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?if ($sec[$name]['security']=='secure'):?>
<div class="title nocontrol"><dt>_(SMB)_ _(User Access)_</dt><i>_(Guests have **read-only** access)_.</i></div>
:smb_secure_access_help:
<div class="clone1">
<span class="clone">_(Read settings from)_</span><i class="fa fa-arrow-left fa-fw"></i>
<span class="wrap"><select name="readusersmb" class="clone" onchange="toggleButton('readusersmb',false)">
<option disabled selected>_(select)_...</option>
<?
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='secure') echo mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='secure') echo mk_option("", $list['name'], compress($list['name']));
}
?>
</select></span><input type="button" id="readusersmb" value="_(Read)_" class="clone" onclick="readUserSMB()" disabled>
</div>
<div class="clone2">
<span class="clone">_(Write settings to)_</span><i class="fa fa-arrow-right fa-fw"></i>
<span class="wrap"><select id="smb2" name="writeusersmb" multiple="multiple" style="display:none" onchange="toggleButton('writeusersmb',this.id)">
<?
$rows = [];
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='secure') $rows[] = mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='secure') $rows[] = mk_option("", $list['name'], compress($list['name']));
}
if ($rows) echo "<option>("._('All').")</option>";
foreach ($rows as $row) echo $row;
?>
</select></span><input type="button" id="writeusersmb" value="_(Write)_" class="clone" onclick="writeUserSMB()" disabled>
</div>
<form markdown="1" name="smb_user_edit" method="POST" action="/update.htm" target="progressFrame" onchange="toggleButton('writeusersmb',true);$('#smb2').dropdownchecklist('disable')">
<input type="hidden" name="shareName" value="<?=htmlspecialchars($name)?>">
<?input_secure_users($sec)?>
&nbsp;
: <input type="submit" name="changeShareAccess" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?elseif ($sec[$name]['security']=='private'):?>
<div class="title nocontrol"><dt>_(SMB)_ _(User Access)_</dt><i>_(Guests have **no** access)_.</i></div>
:smb_private_access_help:
<div class="clone1">
<span class="clone">_(Read settings from)_</span><i class="fa fa-arrow-left fa-fw"></i>
<span class="wrap"><select name="readusersmb" class="clone" onchange="toggleButton('readusersmb',false)">
<option disabled selected>_(select)_...</option>
<?
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='private') echo mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='private') echo mk_option("", $list['name'], compress($list['name']));
}
?>
</select></span><input type="button" id="readusersmb" value="_(Read)_" class="clone" onclick="readUserSMB()" disabled>
</div>
<div class="clone2">
<span class="clone">_(Write settings to)_</span><i class="fa fa-arrow-right fa-fw"></i>
<span class="wrap"><select id="smb2" name="writeusersmb" multiple="multiple" style="display:none" onchange="toggleButton('writeusersmb',this.id)">
<?
$rows = [];
if (isset($disks[$name])) {
foreach (array_filter($disks,'clone_list') as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='private') $rows[] = mk_option("", $list['name'], _(my_disk($list['name']),3));
} else {
foreach ($shares as $list) if ($list['name']!=$name && $sec[$list['name']]['security']=='private') $rows[] = mk_option("", $list['name'], compress($list['name']));
}
if ($rows) echo "<option>("._('All').")</option>";
foreach ($rows as $row) echo $row;
?>
</select></span><input type="button" id="writeusersmb" value="_(Write)_" class="clone" onclick="writeUserSMB()" disabled>
</div>
<form markdown="1" name="smb_user_edit" method="POST" action="/update.htm" target="progressFrame" onchange="toggleButton('writeusersmb',true);$('#smb2').dropdownchecklist('disable')">
<input type="hidden" name="shareName" value="<?=htmlspecialchars($name)?>">
<?input_private_users($sec)?>
&nbsp;
: <input type="submit" name="changeShareAccess" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?endif;?>
<script>
$(function() {
checkShareSettingsSMB(document.smb_edit);
initDropdownSMB(false);
<?if ($tabbed):?>
$('#tab'+$('input[name$="tabs"]').length).bind({click:function(){initDropdownSMB(true);}});
<?endif;?>
<?if (count($users)==1):?>
toggleButton('readusersmb',true);
toggleButton('writeusersmb',true);
$('#smb2').dropdownchecklist('disable');
<?endif;?>
});
function checkShareSettingsSMB(form) {
form.shareVolsizelimit.disabled = (form.shareExport.value.indexOf("et") == -1);
}
function initDropdownSMB(reset) {
if (reset) {
$('#smb1').dropdownchecklist('destroy');
$('#smb2').dropdownchecklist('destroy');
}
$("#smb1").dropdownchecklist({firstItemChecksAll:true, emptyText:"_(select)_...", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
$("#smb2").dropdownchecklist({firstItemChecksAll:true, emptyText:"_(select)_...", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
}
function readSMB() {
var form = document.smb_edit;
var name = $('select[name="readsmb"]').val();
$.get('/webGui/include/ProtocolData.php',{protocol:'smb',name:name},function(json) {
var data = $.parseJSON(json);
form.shareExport.value = data.export;
form.shareFruit.value = data.fruit;
form.shareSecurity.value = data.security;
});
$(form).find('select').trigger('change');
}
function writeSMB(data,n,i) {
if (data) {
if (n<i) {
$.post('/update.htm',data[n], function(){setTimeout(function(){writeSMB(data,++n,i);},3000);});
} else {
toggleButton('writesmb',false);
$('div.spinner.fixed').hide();
}
} else {
var data = [], i = 0;
$('select#smb1 option').map(function() {
if ($(this).prop('selected')==true && $(this).val()!='(_(All)_)') {
data[i] = {};
data[i]['shareName'] = $(this).val();
data[i]['shareExport'] = '<?=addslashes(htmlspecialchars($sec[$name]['export']))?>';
data[i]['shareFruit'] = '<?=addslashes(htmlspecialchars($sec[$name]['fruit']))?>';
data[i]['shareSecurity'] = '<?=addslashes(htmlspecialchars($sec[$name]['security']))?>';
data[i]['changeShareSecurity'] = 'Apply';
i++;
}
});
toggleButton('writesmb',true);
$('div.spinner.fixed').show('slow');
writeSMB(data,0,i);
}
}
function readUserSMB() {
var form = document.smb_user_edit;
var name = $('select[name="readusersmb"]').val();
var users = {};
<?
foreach ($users as $user) {
if ($user['name'] == "root") continue;
echo "users['{$user['name']}'] = {$user['idx']};\n";
}
?>
$.get('/webGui/include/ProtocolData.php',{protocol:'smb',name:name},function(json) {
var data = $.parseJSON(json);
var readList = data.readList.split(',');
var writeList = data.writeList.split(',');
$(form).find('select[name^="userAccess."]').each(function(){$(this).val('no-access');});
for (var i=0; i < readList.length; i++) $(form).find('select[name="userAccess.'+users[readList[i]]+'"]').val('read-only');
for (var i=0; i < writeList.length; i++) $(form).find('select[name="userAccess.'+users[writeList[i]]+'"]').val('read-write');
});
$(form).find('select').trigger('change');
}
function writeUserSMB(data,n,i) {
if (data) {
if (n<i) {
$.post('/update.htm',data[n], function(){setTimeout(function(){writeUserSMB(data,++n,i);},3000);});
} else {
toggleButton('writeusersmb',false);
$('div.spinner.fixed').hide();
}
} else {
var data = [], i = 0;
$('select#smb2 option').map(function() {
if ($(this).prop('selected')==true && $(this).val()!='(_(All)_)') {
data[i] = {};
data[i]['shareName'] = $(this).val();
data[i]['userAccess.0'] = 'no-access';
<?
$read_list = explode(",", $sec[$name]['readList']);
$write_list = explode(",", $sec[$name]['writeList']);
foreach ($users as $user) {
if ($user['name'] == "root") continue;
$idx = $user['idx'];
$userAccess = null;
if ($sec[$name]['security']=='secure') {
$userAccess = in_array($user['name'], $write_list) ? "read-write" : "read-only";
} elseif ($sec[$name]['security'] == 'private') {
$userAccess = in_array($user['name'], $write_list) ? "read-write" : (in_array($user['name'], $read_list) ? "read-only" : "no-access");
}
if ($userAccess) echo "data[i]['userAccess.$idx'] = '$userAccess';\n";
}
?>
data[i]['changeShareAccess'] = 'Apply';
i++;
}
});
toggleButton('writeusersmb',true);
$('div.spinner.fixed').show('slow');
writeUserSMB(data,0,i);
}
}
</script>
+134
View File
@@ -0,0 +1,134 @@
Menu="Device:2 New:2"
Title="Self-Test"
Tag="wrench"
Cond="strpos(_var($disks[$name],'status'),'_NP')===false"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$date = date('Ymd-Hi');
$file = _var($disk,'id','no-id')."-$date.txt";
$zip = str_replace(' ','_',strtolower(_var($var,'NAME','tower')))."-smart-$date.zip";
$long = !isset($disks[$name]['spindownDelay']) || _var($disks[$name],'spindownDelay')==0 || (_var($disks[$name],'spindownDelay')==-1 && _var($var,'spindownDelay')==0);
?>
_(Download SMART report)_:
: <input type='button' value="_(Download)_" onclick='saveSMART()'>
_(SMART self-test history)_:
: <input type="button" value="_(Show)_" id="toggle_log" onclick="selftestLog()">
:selftest_history_help:
<pre id="selftest" style="display:none"></pre>
_(SMART error log)_:
: <input type="button" value="_(Show)_" id="toggle_error" onclick="errorLog()">
:selftest_error_log_help:
<pre id="errorlog" style="display:none"></pre>
_(SMART short self-test)_:
: <input type='button' value="_(Start)_" id='short_test' onclick="startShortTest()">
:selftest_short_test_help:
_(SMART extended self-test)_:
: <input type='button' value="_(Start)_" id='long_test' onclick="startLongTest()"<?=$long ? ">" : " disabled> _(Disable **Spin down delay** to run a SMART extended self-test)_"?>
:selftest_long_test_help:
_(Last SMART test result)_:
: <span id="test_result"><i class='fa fa-circle-o-notch fa-spin fa-fw'></i></span>
:selftest_result_help:
<script>
function cleanUp() {
if (document.hasFocus()) {
$('input[value="_(Downloading)_..."]').val("_(Download)_").prop('disabled',false);
$.post('/webGui/include/Download.php',{cmd:'delete',file:'<?=addslashes(htmlspecialchars($file))?>'});
$.post('/webGui/include/Download.php',{cmd:'delete',file:'<?=addslashes(htmlspecialchars($zip))?>'});
} else {
setTimeout(cleanUp,4000);
}
}
function saveSMART() {
$('input[value="_(Download)_"]').val('_(Downloading)_...').prop('disabled',true);
$.post('/webGui/include/SmartInfo.php',{cmd:'save',port:'<?=$dev?>',name:'<?=$name?>',file:'<?=addslashes(htmlspecialchars($file))?>'}, function() {
$.post('/webGui/include/Download.php',{cmd:'save',source:'<?=addslashes(htmlspecialchars($file))?>',file:'<?=addslashes(htmlspecialchars($zip))?>'},function(zip) {
location = zip;
setTimeout(cleanUp,4000);
});
});
}
function testUpdate(init) {
$.post('/webGui/include/SmartInfo.php',{cmd:'update',port:'<?=$dev?>',name:'<?=$name?>',csrf:'<?=$var['csrf_token']?>'},function(data) {
$('#test_result').html(data);
if (data.indexOf('%')>=0) {
if ($('#smart_selftest').length) {
$('#smart_selftest').html('<i class="fa fa-camera"></i> _(SMART self-test in progress)_...');
}
if (!init) timers.testUpdate = setTimeout(testUpdate,3000);
} else {
if ($('#smart_selftest').length) $('#smart_selftest').html('');
$('#short_test').val("_(Start)_");
$('#long_test').val("_(Start)_");
if (!init) {
$.removeCookie('test.<?=$dev?>');
}
}
});
}
function selftestLog() {
$('#selftest').toggle('slow');
var text = $('#toggle_log').val()=="_(Show)_" ? "_(Hide)_" : "_(Show)_";
$('#toggle_log').val(text);
}
function errorLog() {
$('#errorlog').toggle('slow');
var text = $('#toggle_error').val()=="_(Show)_" ? "_(Hide)_" : "_(Show)_";
$('#toggle_error').val(text);
}
function startShortTest() {
if ($('#short_test').val()=="_(Start)_") {
$('#short_test').val("_(Stop)_");
$('#long_test').attr('disabled','disabled');
$.cookie('test.<?=$dev?>','short',{expires:365});
$.post('/webGui/include/SmartInfo.php',{cmd:'short',port:'<?=$dev?>',name:'<?=$name?>'},function(){timers.testUpdate = setTimeout(testUpdate,0);});
} else {
clearTimeout(timers.testUpdate);
$.removeCookie('test.<?=$dev?>');
$.post('/webGui/include/SmartInfo.php',{cmd:'stop',port:'<?=$dev?>',name:'<?=$name?>'},function(){setTimeout(testUpdate,0);});
}
}
function startLongTest() {
if ($('#long_test').val()=="_(Start)_") {
$('#long_test').val("_(Stop)_");
$('#short_test').attr('disabled','disabled');
$.cookie('test.<?=$dev?>','long',{expires:365});
$.post('/webGui/include/SmartInfo.php',{cmd:'long',port:'<?=$dev?>',name:'<?=$name?>'},function(){timers.testUpdate = setTimeout(testUpdate,0);});
} else {
clearTimeout(timers.testUpdate);
$.removeCookie('test.<?=$dev?>');
$.post('/webGui/include/SmartInfo.php',{cmd:'stop',port:'<?=$dev?>',name:'<?=$name?>'},function(){setTimeout(testUpdate,0);});
}
}
$(function() {
var smarttest = $.cookie('test.<?=$dev?>');
testUpdate(smarttest===undefined);
if (smarttest !== undefined) $('#'+smarttest+'_test').val("_(Stop)_").removeAttr('disabled');
$.post('/webGui/include/SmartInfo.php',{cmd:'selftest',port:'<?=$dev?>',name:'<?=$name?>'},function(data){$('#selftest').html(data);});
$.post('/webGui/include/SmartInfo.php',{cmd:'errorlog',port:'<?=$dev?>',name:'<?=$name?>'},function(data){$('#errorlog').html(data);});
});
</script>
+4
View File
@@ -0,0 +1,4 @@
Menu="Tasks:4"
Type="xmenu"
Tabs="false"
Code="e924"
+80
View File
@@ -0,0 +1,80 @@
Type="xmenu"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
function clone_list($disk) {
global $pools;
return strpos($disk['status'],'_NP')===false && ($disk['type']=='Data' || in_array($disk['name'],$pools));
}
if ($name) {
$refs = []; $n = $i = 0;
// Natural sorting of share names
uksort($shares,'strnatcasecmp');
foreach ($shares as $ref) {
$sname = $ref['name'];
$refs[] = $sname;
if ($sname==$name) $i = $n;
$n++;
}
$end = count($refs)-1;
if ($end >= 0) {
$prev = urlencode($i>0 ? $refs[$i-1] : $refs[$end]);
$next = urlencode($i<$end ? $refs[$i+1] : $refs[0]);
} else {
$prev = $next = '';
}
} else {
$tabbed = false;
}
?>
<style>
div.clone1{position:absolute;right:10px;margin-top:0}
div.clone2{position:absolute;right:10px;margin-top:48px}
span.input{display:inline-block;width:330px}
<?if ($themes1):?>
span.wrap{display:inline-block;width:128px}
select.clone{min-width:123px;max-width:123px;margin-right:0}
<?else:?>
span.wrap{display:inline-block;width:150px}
select.clone{min-width:145px;max-width:145px;margin-right:0}
<?endif;?>
input.clone{margin-left:8px;margin-right:0}
span.clone{margin-right:4px}
</style>
<script>
function toggleButton(button,id) {
var disabled = true;
switch (id) {
case false:
case true:
disabled = id;
break;
default:
$('select#'+id+' option').each(function(){if ($(this).prop('selected')==true) disabled = false;});
}
$('input#'+button).prop('disabled',disabled);
}
<?if ($name):?>
var ctrl = '<span class="ctrl1 status <?=$tabbed?'vhshift':'vshift'?>"><a href="/Shares/Share?name=<?=$prev?>" title="_(previous user share)_"><button type="button" style="margin-right:4px"><i class="fa fa-chevron-left fa-fw"></i></button></a><a href="/Shares/Share?name=<?=$next?>" title="_(next user share)_"><button type="button"><i class="fa fa-chevron-right fa-fw"></i></button></a></span>';
$(function() {
<?if ($tabbed):?>
$('.tabs').append(ctrl);
<?else:?>
$('div[class=title]:first').append(ctrl);
<?endif;?>
});
<?endif;?>
</script>
+598
View File
@@ -0,0 +1,598 @@
Menu="Share:1"
Title="Share Settings"
Tag="share-alt-square"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$width = [123,300];
if ($name == "") {
// default values when adding new share
$share = ["nameOrig" => "",
"name" => "",
"comment" => "",
"allocator" => "highwater",
"floor" => "",
"splitLevel" => "",
"include" => "",
"exclude" => "",
"useCache" => "no",
"cachePool" => "",
"cow" => "auto"
];
} elseif (array_key_exists($name, $shares)) {
// edit existing share
$share = $shares[$name];
} else {
// handle share deleted case
echo "<p class='notice'>"._('Share')." '".htmlspecialchars($name)."' "._('has been deleted').".</p><input type='button' value=\""._('Done')."\" onclick='done()'>";
return;
}
// Check for non existent pool device
if ($share['cachePool'] && !in_array($share['cachePool'],$pools)) $share['useCache'] = "no";
function globalInclude($name) {
global $var;
return substr($name,0,4)=='disk' && (!$var['shareUserInclude'] || in_array($name,explode(',',$var['shareUserInclude'])));
}
function sanitize(&$val) {
$data = explode('.',str_replace([' ',','],['','.'],$val));
$last = array_pop($data);
$val = count($data) ? implode($data).".$last" : $last;
}
function presetSpace($val) {
global $disks,$shares,$name,$pools,$display;
if (!$val or strcasecmp($val,'NaN')==0) return;
sanitize($val);
$small = [];
foreach (data_filter($disks) as $disk) $small[] = _var($disk,'fsSize');
$fsSize[""] = min(array_filter($small));
foreach ($pools as $pool) $fsSize[$pool] = _var($disks[$pool],'fsSize',0);
$pool = _var($shares[$name],'cachePool');
$size = _var($fsSize,$pool,0);
$size = $size>0 ? round(100*$val/$size,1) : 0;
$unit = '%';
if ($size < 1) {
$units = ['KB','MB','GB','TB','PB','EB','ZB','YB'];
$base = $val>0 ? floor(log($val,1000)) : 0;
$size = round($val/pow(1000,$base),1);
$unit = _var($units,$base);
}
[$dot,$comma] = str_split(_var($display,'number','.,'));
return $size>0 ? number_format($size,$size-floor($size)?1:0,$dot,$comma).' '.$unit : '';
}
function fsSize() {
global $disks,$pools;
$fsSize = $small = [];
foreach (data_filter($disks) as $disk) $small[] = _var($disk,'fsSize');
$fsSize[] = '"":"'.min(array_filter($small)).'"';
foreach ($pools as $pool) $fsSize[] = '"'.$pool.'":"'._var($disks[$pool],'fsSize',0).'"';
return implode(',',$fsSize);
}
function fsType() {
global $disks,$pools;
$fsType = [];
foreach ($pools as $pool) $fsType[] = '"'.$pool.'":"'.str_replace('luks:','',_var($disks[$pool],'fsType')).'"';
return implode(',',$fsType);
}
function primary() {
global $share;
return $share['useCache']=='no' ? '' : $share['cachePool'];
}
function secondary() {
global $share;
return in_array($share['useCache'],['no','only']) ? '0' : '1';
}
function direction() {
global $share;
return $share['useCache']=='prefer' ? '1' : '0';
}
// global shares include/exclude
$myDisks = array_filter(array_diff(array_keys(array_filter($disks,'my_disks')), explode(',',$var['shareUserExclude'])), 'globalInclude');
?>
<style>
div.shade-white{background-color:#ededed;margin-top:10px;padding:8px 0 3px 0}
div.shade-black{background-color:#212121;margin-top:10px;padding:8px 0 3px 0}
div.shade-azure{background-color:#edeaef;margin-top:10px;padding:8px 0 3px 0}
div.shade-gray{background-color:#121510;margin-top:10px;padding:8px 0 3px 0}
#s1,#s2,#s3,#s4,#s5,#autosize,.empty,.full2,#zfs-name{display:none}
i.fa-info.i{margin-right:10px}
<?if ($themes1):?>
form[name=share_edit]{margin-top:-20px}
<?endif;?>
</style>
:share_edit_global1_help:
<?if ($name):?>
:share_edit_global2_help:
<?endif;?>
<div class="clone1">
<span class="clone">_(Read settings from)_</span><i class="fa fa-arrow-left fa-fw"></i>
<span class="wrap"><select name="readshare" class="clone" onchange="toggleButton('readshare',false)">
<option disabled selected>_(select)_...</option>
<?
foreach ($shares as $list) if ($list['name']!=$name || !$name) echo mk_option("", $list['name'], compress($list['name']));
?>
</select></span><input type="button" id="readshare" value="_(Read)_" class="clone" onclick="readShare()" disabled>
</div>
<?if ($name):?>
<div class="clone2">
<span class="clone">_(Write settings to)_</span><i class="fa fa-arrow-right fa-fw"></i>
<span class="wrap"><select id="s5" name="writeshare" multiple onchange="toggleButton('writeshare',this.id)">
<?
$rows = [];
foreach ($shares as $list) if ($list['name']!=$name) $rows[] = mk_option("", $list['name'], compress($list['name']));
if ($rows) echo "<option>("._('All').")</option>";
foreach ($rows as $row) echo $row;
?>
</select></span><input type="button" id="writeshare" value="_(Write)_" class="clone" onclick="writeShare()" disabled>
</div>
<?endif;?>
<form markdown="1" name="share_edit" method="POST" action="/update.htm" target="progressFrame" onsubmit="return prepareEdit()"<?=$name?" onchange=\"toggleButton('writeshare',true);$('#s5').dropdownchecklist('disable')\">":">"?>
<input type="hidden" name="shareNameOrig" value="<?=htmlspecialchars($share['nameOrig'])?>">
<input type="hidden" name="shareUseCache" value="<?=$share['useCache']?>">
<input type="hidden" name="shareAllocator" value="">
<input type="hidden" name="shareSplitLevel" value="">
<input type="hidden" name="shareInclude" value="">
<input type="hidden" name="shareExclude" value="">
<?if (_var($share,'exclusive')!="no"):?>
<input type="hidden" name="shareFloor" value="">
<?endif;?>
<div markdown="1" class="shade-<?=$display['theme']?>">
_(Share name)_:
: <input type="text" id="shareName" name="shareName" maxlength="40" autocomplete="off" spellcheck="false" value="<?=htmlspecialchars($name)?>" oninput="checkName(this.value)" title="_(Hidden share names are not allowed)_" pattern="^[^\.].*"><span id="zfs-name" class="orange-text"><i class="fa fa-warning"></i> _(Share name contains invalid characters for ZFS use)_</span>
:share_edit_name_help:
_(Comments)_:
: <input type="text" name="shareComment" maxlength="256" autocomplete="off" spellcheck="false" value="<?=htmlspecialchars($share['comment'])?>">
:share_edit_comments_help:
<?if (_var($share,'exclusive')=="no"):?>
<div markdown="1">
_(Minimum free space)_:
: <span class="input"><input type="text" name="shareFloor" maxlength="16" autocomplete="off" spellcheck="false" class="narrow" value="<?=presetSpace($share['floor'])?>" placeholder="0"></span><span id="autosize"><i class="fa fa-info i"></i>_(Calculated free space value)_</span>
:share_edit_free_space_help:
</div>
<?endif;?>
<?if ($name):?>
<div markdown="1" class="empty">
_(Share status)_:
: _(Share is empty)_
:share_edit_status_help:
</div>
<div markdown="1" class="full">
_(Share status)_:
: <span class="full1">&nbsp;</span><span class="full2">_(Share contains data)_</span>
:share_edit_delete_help:
</div>
<?if (_var($share,'exclusive')=="yes"):?>
_(Exclusive access)_:
: _(Yes)_
:share_edit_exclusive_access_help:
<?else:?>
_(Exclusive access)_:
: _(No)_
:share_edit_exclusive_access_help:
<?endif;?>
<?endif;?>
</div>
<div markdown="1" class="shade-<?=$display['theme']?>">
_(Primary storage (for new files and folders))_:
: <select id="primary" name="shareCachePool" onchange="form.shareFloor.value='';updateScreen(z(4),'slow')">
<?=mk_option(primary(),'',_('Array'))?>
<?foreach ($pools as $pool):?>
<?if ($disks[$pool]['devices']) echo mk_option(primary(),$pool,my_disk($pool),$disks[$pool]['shareEnabled']=='yes'?"":"disabled")?>
<?endforeach;?>
</select>
:share_edit_primary_storage_help:
<div markdown="1" id="cow-setting">
_(Enable Copy-on-write)_:
: <span class="input"><select name="shareCOW"<?if ($name):?> disabled<?endif;?>>
<?=mk_option($share['cow'], "no", _('No'))?>
<?=mk_option($share['cow'], "auto", _('Auto'))?>
</select></span><?if ($name):?><i class='fa fa-info i'></i>_(Set when adding new share only)_<?endif;?>
:share_edit_copy_on_write_help:
</div>
<div markdown="1" id="moreSettings1">
_(Allocation method)_:
: <select name="shareAllocator1">
<?=mk_option($share['allocator'], "highwater", _('High-water'))?>
<?=mk_option($share['allocator'], "fillup", _('Fill-up'))?>
<?=mk_option($share['allocator'], "mostfree", _('Most-free'))?>
</select>
:share_edit_allocation_method_help:
_(Split level)_:
: <select name="shareSplitLevel1">
<?=mk_option($share['splitLevel'], "", _('Automatically split any directory as required'))?>
<?=mk_option($share['splitLevel'], "1", _('Automatically split only the top level directory as required'))?>
<?=mk_option($share['splitLevel'], "2", _('Automatically split only the top two directory levels as required'))?>
<?=mk_option($share['splitLevel'], "3", _('Automatically split only the top three directory levels as required'))?>
<?=mk_option($share['splitLevel'], "4", _('Automatically split only the top four directory levels as required'))?>
<?=mk_option($share['splitLevel'], "5", _('Automatically split only the top five directory levels as required'))?>
<?=mk_option($share['splitLevel'], "0", _('Manual: do not automatically split directories'))?>
</select>
:share_edit_split_level_help:
_(Included disk(s))_:
: <select id="s1" name="shareInclude1" multiple>
<?foreach ($myDisks as $disk):?>
<?=mk_option_luks($disk, $share['include'], strstr(_var($disks[$disk],'fsType'),':',true))?>
<?endforeach;?>
</select>
:share_edit_included_disks_help:
_(Excluded disk(s))_:
: <select id="s2" name="shareExclude1" multiple>
<?foreach ($myDisks as $disk):?>
<?=mk_option_luks($disk, $share['exclude'], strstr(_var($disks[$disk],'fsType'),':',true))?>
<?endforeach;?>
</select>
:share_edit_excluded_disks_help:
</div>
</div>
<div markdown="1" class="shade-<?=$display['theme']?>">
_(Secondary storage)_:
: <select id="secondary" onchange="updateScreen(z(4),'slow')">
<?=mk_option(secondary(),'0',_('None'))?>
<?=mk_option(secondary(),'1',_('Array'))?>
</select>
:share_edit_secondary_storage_help:
<div markdown="1" id="moreSettings2">
_(Allocation method)_:
: <select name="shareAllocator2">
<?=mk_option($share['allocator'], "highwater", _('High-water'))?>
<?=mk_option($share['allocator'], "fillup", _('Fill-up'))?>
<?=mk_option($share['allocator'], "mostfree", _('Most-free'))?>
</select>
:share_edit_allocation_method_help:
_(Split level)_:
: <select name="shareSplitLevel2">
<?=mk_option($share['splitLevel'], "", _('Automatically split any directory as required'))?>
<?=mk_option($share['splitLevel'], "1", _('Automatically split only the top level directory as required'))?>
<?=mk_option($share['splitLevel'], "2", _('Automatically split only the top two directory levels as required'))?>
<?=mk_option($share['splitLevel'], "3", _('Automatically split only the top three directory levels as required'))?>
<?=mk_option($share['splitLevel'], "4", _('Automatically split only the top four directory levels as required'))?>
<?=mk_option($share['splitLevel'], "5", _('Automatically split only the top five directory levels as required'))?>
<?=mk_option($share['splitLevel'], "0", _('Manual: do not automatically split directories'))?>
</select>
:share_edit_split_level_help:
_(Included disk(s))_:
: <select id="s3" name="shareInclude2" multiple>
<?foreach ($myDisks as $disk):?>
<?=mk_option_luks($disk, $share['include'], strstr(_var($disks[$disk],'fsType'),':',true))?>
<?endforeach;?>
</select>
:share_edit_included_disks_help:
_(Excluded disk(s))_:
: <select id="s4" name="shareExclude2" multiple>
<?foreach ($myDisks as $disk):?>
<?=mk_option_luks($disk, $share['exclude'], strstr(_var($disks[$disk],'fsType'),':',true))?>
<?endforeach;?>
</select>
:share_edit_excluded_disks_help:
</div>
</div>
<div markdown="1" class="shade-<?=$display['theme']?>">
<div markdown="1" id="moverDirection1">
_(Mover action)_:
: <span class="input"><select id="direction" onchange="updateScreen(z(3),'slow')">
<?=mk_option(direction(),'0','')?>
<?=mk_option(direction(),'1','')?>
</select></span><span id="moverAction1"></span>
:share_edit_mover_action_help:
</div>
<div markdown="1" id="moverDirection2">
_(Mover action)_:
: <span class="input"><select disabled>
<?=mk_option('','',"_(Not used)_")?>
</select></span><span id="moverAction2"></span>
:share_edit_mover_action_help:
</div>
</div>
<?if (!$name):?>
&nbsp;
: <input type="submit" name="cmdEditShare" value="_(Add Share)_" onclick="this.value='Add Share'"><input type="button" value="_(Done)_" onclick="done()">
<?else:?>
<div markdown="1" class="empty">
_(Delete)_<input type="checkbox" name="confirmDelete" onchange="chkDelete(this.form, document.getElementById('cmdEditShare'));">
: <input type="submit" id="cmdEditShare" name="cmdEditShare" value="_(Apply)_" onclick="if (this.value=='_(Delete)_') this.value='Delete'; else this.value='Apply'" disabled><input type="button" value="_(Done)_" onclick="done()">
</div>
<div markdown="1" class="full">
&nbsp;
: <input type="submit" name="cmdEditShare" value="_(Apply)_" onclick="this.value='Apply'" disabled><input type="button" value="_(Done)_" onclick="done()">
</div>
<?endif;?>
</form>
<script>
var form = document.share_edit;
$(function() {
<?if ($name):?>
$.post('/webGui/include/ShareList.php',{scan:"<?=$name?>"},function(e){
if (e==1) {$('.empty').show(); $('.full').hide();} else {$('.full1').hide(); $('.full2').show();}
});
<?endif;?>
initDropdown(false,true);
<?if ($tabbed):?>
$('#tab1').bind({click:function(){initDropdown(true,true);}});
<?endif;?>
updateScreen(form.shareUseCache.value);
if ($.cookie('autosize-'+$('#shareName').val())) $('#autosize').show();
checkName($('#shareName').val());
});
function initDropdown(remove,create) {
if (remove) {
$('#s1').dropdownchecklist('destroy');
$('#s2').dropdownchecklist('destroy');
$('#s3').dropdownchecklist('destroy');
$('#s4').dropdownchecklist('destroy');
<?if ($name):?>
$('#s5').dropdownchecklist('destroy');
<?endif;?>
}
if (create) {
$('#s1').dropdownchecklist({emptyText:"_(All)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
$('#s2').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
$('#s3').dropdownchecklist({emptyText:"_(All)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
$('#s4').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
<?if ($name):?>
$("#s5").dropdownchecklist({firstItemChecksAll:true, emptyText:"_(select)_...", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
<?endif;?>
}
}
function z(i) {
switch (i) {
case 0: return $('#primary').prop('selectedIndex');
case 1: return $('#secondary').prop('selectedIndex');
case 2: return $('#direction').prop('selectedIndex');
case 3: return z(2)==0 ? 'yes' : 'prefer';
case 4: return z(0)==0 ? 'no' : (z(1)==0 ? 'only' : z(3));
}
}
function updateCOW(i,slow) {
const fsType = {<?=fsType()?>};
if (fsType[i]=='btrfs') $('#cow-setting').show(slow); else $('#cow-setting').hide(slow);
}
function updateScreen(cache,slow) {
switch (cache) {
case 'no':
$('#primary option:eq('+z(0)+')').prop('selected',true);
$('#secondary option:eq(0)').prop('selected',true);
$('#secondary option:eq(1)').prop('disabled',true);
$('#moverDirection1').hide();
$('#moverDirection2').show();
$('#moreSettings1').show(slow);
$('#moreSettings2').hide(slow);
$('#cow-setting').hide(slow);
form.shareAllocator.disabled = false;
form.shareSplitLevel.disabled = false;
$('#s1').dropdownchecklist('enable');
$('#s2').dropdownchecklist('enable');
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
break;
case 'yes':
$('#primary option:eq('+z(0)+')').prop('selected',true);
$('#secondary option:eq('+z(1)+')').prop('selected',true);
$('#secondary option:eq(1)').prop('disabled',false);
$('#moverDirection1 option:eq(0)').text($('#primary option:eq('+z(0)+')').text()+' → '+$('#secondary option:eq('+z(1)+')').text());
$('#moverDirection1 option:eq(1)').text($('#secondary option:eq('+z(1)+')').text()+' → '+$('#primary option:eq('+z(0)+')').text());
$('#moverDirection1').val('0').show();
$('#moverDirection2').hide();
$('#moreSettings1').hide(slow);
$('#moreSettings2').show(slow);
updateCOW(form.shareCachePool.value,slow);
form.shareAllocator.disabled = false;
form.shareSplitLevel.disabled = false;
$('#s3').dropdownchecklist('enable');
$('#s4').dropdownchecklist('enable');
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Primary storage to Secondary storage)_");
break;
case 'only':
$('#primary option:eq('+z(0)+')').prop('selected',true);
$('#secondary option:eq('+z(1)+')').prop('selected',true);
$('#secondary option:eq(1)').prop('disabled',false);
$('#moverDirection1').hide();
$('#moverDirection2').show();
$('#moreSettings1').hide(slow);
$('#moreSettings2').hide(slow);
updateCOW(form.shareCachePool.value,slow);
form.shareAllocator.disabled = true;
form.shareSplitLevel.disabled = true;
$('#s1').dropdownchecklist('disable');
$('#s2').dropdownchecklist('disable');
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
break;
case 'prefer':
$('#primary option:eq('+z(0)+')').prop('selected',true);
$('#secondary option:eq('+z(1)+')').prop('selected',true);
$('#secondary option:eq(1)').prop('disabled',false);
$('#moverDirection1 option:eq(0)').text($('#primary option:eq('+z(0)+')').text()+' → '+$('#secondary option:eq('+z(1)+')').text());
$('#moverDirection1 option:eq(1)').text($('#secondary option:eq('+z(1)+')').text()+' → '+$('#primary option:eq('+z(0)+')').text());
$('#moverDirection1').val('1').show();
$('#moverDirection2').hide();
$('#moreSettings1').hide(slow);
$('#moreSettings2').show(slow);
updateCOW(form.shareCachePool.value,slow);
form.shareAllocator.disabled = false;
form.shareSplitLevel.disabled = false;
$('#s3').dropdownchecklist('enable');
$('#s4').dropdownchecklist('enable');
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Secondary storage to Primary storage)_");
break;
}
}
function unite(field) {
var list = [];
for (var i=0,item; item=field.options[i]; i++) if (item.selected) list.push(item.value);
return list.join(',');
}
function setFloor(val) {
const fsSize = {<?=fsSize()?>};
const units = ['K','M','G','T','P','E','Z','Y'];
var full = fsSize[$('#primary').val()];
var size = parseInt(full * 0.1); // 10% of available size
var number = val.replace(/[A-Z%\s]/gi,'').replace(',','.').split('.');
var last = number.pop();
number = number.length ? number.join('')+'.'+last : last;
if (number==0 && size>0) {
size = size.toString()
$.cookie('autosize-'+$('#shareName').val(),'1',{expires:365});
} else {
size = val;
$.removeCookie('autosize-'+$('#shareName').val());
}
var unit = size.replace(/[0-9.,\s]/g,'');
if (unit=='%') {
number = (number > 0 && number <= 100) ? parseInt(full * number / 100) : '';
} else {
var base = unit.length==2 ? 1000 : (unit.length==1 ? 1024 : 0);
number = base>0 ? number * Math.pow(base,(units.indexOf(unit.toUpperCase().replace('B',''))||0)) : size;
}
return isNaN(number) ? '' : number;
}
// Compose input fields
function prepareEdit() {
// Test share name validity
var share = form.shareName.value.trim();
if (share.length==0) {
swal({title:"_(Missing share name)_",text:"_(Enter a name for the share)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
var reserved = [<?=implode(',',array_map('escapestring',explode(',',$var['reservedNames'])))?>];
if (reserved.includes(share)) {
swal({title:"_(Invalid share name)_",text:"_(Do not use reserved names)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
var pools = [<?=implode(',',array_map('escapestring',$pools))?>];
if (pools.includes(share)) {
swal({title:"_(Invalid share name)_",text:"_(Do not use pool names)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
if (share.match('[:\\\/*<>|"?]')) {
swal({title:"_(Invalid Characters)_",text:"_(You cannot use the following within share names)_"+'<b> \\ / : * < > | " ?</b>',type:'error',html:true,confirmButtonText:"_(Ok)_"});
return false;
}
// Update settings
form.shareName.value = share;
form.shareUseCache.value = z(4);
form.shareFloor.value = setFloor(form.shareFloor.value);
switch (form.shareUseCache.value) {
case 'no':
form.shareAllocator.value = form.shareAllocator1.value;
form.shareSplitLevel.value = form.shareSplitLevel1.value;
form.shareInclude.value = unite(form.shareInclude1);
form.shareExclude.value = unite(form.shareExclude1);
break;
case 'yes':
case 'prefer':
form.shareAllocator.value = form.shareAllocator2.value;
form.shareSplitLevel.value = form.shareSplitLevel2.value;
form.shareInclude.value = unite(form.shareInclude2);
form.shareExclude.value = unite(form.shareExclude2);
break;
}
return true;
}
function readShare() {
var name = $('select[name="readshare"]').val();
initDropdown(true,false);
$.get('/webGui/include/ShareData.php',{name:name},function(json) {
var data = $.parseJSON(json);
form.shareAllocator.value = data.allocator;
form.shareFloor.value = data.floor;
form.shareSplitLevel.value = data.splitLevel;
form.shareInclude.value = data.include;
form.shareExclude.value = data.exclude;
form.shareUseCache.value = data.useCache;
form.shareCOW.value = data.cow;
for (var i=0,disk; disk=data.include.split(',')[i]; i++) for (var j=0,include; include=form.shareInclude.options[j]; j++) if (include.value==disk) include.selected=true;
for (var i=0,disk; disk=data.exclude.split(',')[i]; i++) for (var j=0,exclude; exclude=form.shareExclude.options[j]; j++) if (exclude.value==disk) exclude.selected=true;
initDropdown(false,true);
});
$(form).find('select').trigger('change');
}
function writeShare(data,n,i) {
if (data) {
if (n<i) {
$.post('/update.htm',data[n], function(){setTimeout(function(){writeShare(data,++n,i);},3000);});
} else {
toggleButton('writeshare',false);
$('div.spinner.fixed').hide();
}
} else {
var data = [], i = 0;
$('select#s5 option').map(function() {
if ($(this).prop('selected')==true && $(this).val()!='(All)') {
data[i] = {};
data[i]['shareName'] = $(this).val();
data[i]['shareNameOrig'] = $(this).val();
data[i]['shareAllocator'] = '<?=addslashes(htmlspecialchars($share['allocator']))?>';
data[i]['shareFloor'] = '<?=addslashes(htmlspecialchars($share['floor']))?>';
data[i]['shareSplitLevel'] = '<?=addslashes(htmlspecialchars($share['splitLevel']))?>';
data[i]['shareInclude'] = '<?=addslashes(htmlspecialchars($share['include']))?>';
data[i]['shareExclude'] = '<?=addslashes(htmlspecialchars($share['exclude']))?>';
data[i]['shareUseCache'] = '<?=addslashes(htmlspecialchars($share['useCache']))?>';
data[i]['cmdEditShare'] = 'Apply';
i++;
}
});
toggleButton('writeshare',true);
$('div.spinner.fixed').show('slow');
writeShare(data,0,i);
}
}
function checkName(name) {
if (/^[A-Za-z0-9-_.: ]*$/.test(name)) $('#zfs-name').hide(); else $('#zfs-name').show();
}
</script>
+66
View File
@@ -0,0 +1,66 @@
Menu="Shares:1"
Title="User Shares"
Tag="user-circle"
Cond="_var($var,'fsState')!='Stopped' && _var($var,'shareUser')=='e'"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
table.share_status thead tr td:first-child{width:15%}
table.share_status thead tr td:nth-child(n+3){width:9%!important}
table.share_status thead tr td:nth-child(5){width:13%!important}
td.empty{text-align:center;padding-top:12px}
i.fa-fw{margin-right:2px}
</style>
<table class="share_status">
<thead><tr><td>_(Name)_</td><td>_(Comment)_</td><td>_(SMB)_</td><td>_(NFS)_</td><td>_(Storage)_</td><td>_(Size)_</td><td>_(Free)_</td></tr></thead>
<tbody id="shareslist"></tbody>
</table>
<form name="share_form" method="POST" action="<?=htmlspecialchars($path)?>/Share?name=">
<input type="button" id="compute-shares" value="_(Compute All)_" onclick="$(this).prop('disabled',true);shareList('',-1)">
<input type="submit" value="_(Add Share)_">
<input type="button" value="_(Clean Up)_" onclick="cleanup()" id="cleanup-button" disabled>
</form>
:share_list_help:
<script>
function shareList(name,all) {
timers.shareList = setTimeout(function(){$('div.spinner.fixed').show();},500);
$.post('/webGui/include/ShareList.php',{compute:name,path:"<?=rawurlencode($path)?>",all:all},function(data){
clearTimeout(timers.shareList);
$('div.spinner.fixed').hide();
$('#shareslist').html(data);
if (all!=1) $('#compute-shares').prop('disabled',!data||data.indexOf('colspan=')!=-1);
});
}
function computeShare(name,status) {
status.html("<i class='fa fa-circle-o-notch fa-spin'></i> _(Please wait)_...");
shareList(name,1);
}
function cleanup() {
swal({title:"_(CLEAN UP)_",text:"_(Remove unused share configurations)_",type:'info',html:true,animation:'none',showCancelButton:true,closeOnConfirm:false,confirmButtonText:"<?=_('Proceed')?>",cancelButtonText:"<?=_('Cancel')?>"},function(cleanup){
if (!cleanup) return;
$.post('/webGui/include/ShareList.php',{cleanup:1},function(data){
swal({title:"_(CLEAN UP)_",text:"_(Removed share configurations)_: "+data,type:"success",html:true,confirmButtonText:"_(Ok)_"},function(esc){$('#cleanup-button').prop('disabled',true);});
});
});
}
$(function(){
// enable CLEAN_UP button only when unused files are present
$.post('/webGui/include/ShareList.php',{cleanup:0},function(data){if (data>0) $('#cleanup-button').prop('disabled',false);});
shareList('',0);
});
</script>
+128
View File
@@ -0,0 +1,128 @@
Menu="OtherSettings"
Type="xmenu"
Title="Global Share Settings"
Icon="icon-share"
Tag="share-alt"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$disabled = _var($var,'fsState')!='Stopped' ? 'disabled' : '';
$disks = array_filter($disks,'my_disks');
$width = [166,300];
?>
<script>
$(function() {
$('#s1').dropdownchecklist({emptyText:"_(All)_", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
$('#s2').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
presetShare(document.share_settings);
});
// Simulate the original input field
function prepareShare(form) {
var include = '';
for (var i=0,item; item=form.shareUserInclude.options[i]; i++) {
if (item.selected) {
if (include.length) include += ',';
include += item.value;
item.selected = false;
}
}
item = form.shareUserInclude.options[0];
item.value = include;
item.selected = true;
var exclude = '';
for (var i=0,item; item=form.shareUserExclude.options[i]; i++) {
if (item.selected) {
if (exclude.length) exclude += ',';
exclude += item.value;
item.selected = false;
}
}
item = form.shareUserExclude.options[0];
item.value = exclude;
item.selected = true;
}
function presetShare(form,shares) {
var disabled = shares==null ? <?=$disabled ? 'true':'false'?> : shares=='-';
var onOff = disabled ? 'disable':'enable';
form.shareUserInclude.disabled = disabled;
form.shareUserExclude.disabled = disabled;
$('#s1').dropdownchecklist(onOff);
$('#s2').dropdownchecklist(onOff);
}
</script>
<form markdown="1" name="share_settings" method="POST" action="/update.htm" target="progressFrame" onsubmit="prepareShare(this)">
_(Enable disk shares)_:
: <select name="shareDisk" <?=$disabled?>>
<?=mk_option($var['shareDisk'], "no", _('No'))?>
<?=mk_option($var['shareDisk'], "yes", _('Yes'))?>
<?=mk_option($var['shareDisk'], "auto", _('Auto'))?>
</select>
:shares_enable_disk_help:
_(Enable user shares)_:
: <select name="shareUser" onchange="presetShare(this.form,this.value)" <?=$disabled?>>
<?=mk_option($var['shareUser'], "e", _('Yes'))?>
<?=mk_option($var['shareUser'], "-", _('No'))?>
</select>
:shares_enable_shares_help:
_(Included disk(s))_:
: <select id="s1" name="shareUserInclude" multiple="multiple" style="display:none">
<?foreach ($disks as $disk):?>
<?=mk_option_luks(_var($disk,'name'),_var($var,'shareUserInclude'),strstr(_var($disk,'fsType'),':',true))?>
<?endforeach;?>
</select>
:shares_included_disks_help:
_(Excluded disk(s))_:
: <select id="s2" name="shareUserExclude" multiple="multiple" style="display:none">
<?foreach ($disks as $disk):?>
<?=mk_option_luks(_var($disk,'name'),_var($var,'shareUserExclude'),strstr(_var($disk,'fsType'),':',true))?>
<?endforeach;?>
</select>
:shares_excluded_disks_help:
_(Permit exclusive shares)_:
: <select name="shareUserExclusive" <?=$disabled?>>
<?=mk_option($var['shareUserExclusive'], "no", _('No'))?>
<?=mk_option($var['shareUserExclusive'], "yes", _('Yes'))?>
</select>
:shares_exclusive_shares_help:
_(Tunable (support Hard Links))_:
: <select name="fuse_useino" <?=$disabled?>>
<?=mk_option($var['fuse_useino'], "no", _('No'))?>
<?=mk_option($var['fuse_useino'], "yes", _('Yes'))?>
</select>
:shares_tunable_hard_links_help:
_(Tunable (enable Direct IO))_:
: <select name="fuse_directio" <?=$disabled?>>
<?=mk_option($var['fuse_directio'], "auto", _('Auto'))?>
<?=mk_option($var['fuse_directio'], "0", _('No'))?>
<?=mk_option($var['fuse_directio'], "1", _('Yes'))?>
</select>
:shares_tunable_direct_io_help:
&nbsp;
: <input type="submit" name="changeShare" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()"><?if ($disabled):?>*_(Array must be **Stopped** to change)_*<?endif;?>
</form>
+11
View File
@@ -0,0 +1,11 @@
Menu="Tasks:2"
Type="xmenu"
Code="e92a"
---
<?PHP
if ($var['fsState']=="Stopped") {
echo "<p class='notice shift'>"._('Array must be **Started** to view Shares').".</p>";
return;
}
if (count($pages)==2) $tabbed = false;
?>
+190
View File
@@ -0,0 +1,190 @@
Menu="Notifications:2"
Title="SMTP Settings"
Tag="envelope"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
require_once "$docroot/webGui/include/Encryption.php";
$ssmtp['AuthPass'] = base64_decrypt(_var($ssmtp,'AuthPass'));
$incomplete = !_var($ssmtp,'root') || !_var($ssmtp,'server') || !_var($ssmtp,'port') || ((!_var($ssmtp,'AuthUser') || !_var($ssmtp,'AuthPass')) && _var($ssmtp,'AuthMethod')!='none');
?>
<script>
var counter,pid;
$(function() {
$('#testbutton').click(function(){
$('#testresult').html('_(Test running)_:<span class="orange">_(obtaining)_ <span id="testcounter"></span>...</span>');
counter = 20;
mailtest();
$.get('/webGui/include/SMTPtest.php',function(data){clearTimeout(pid); $('#testresult').html(data)});
});
tls(document.smtp_setup);
pwd(document.smtp_setup);
});
function mailcheck(form) {
var email = /^\S+@\S+\.\S+/;
if (!email.test(form.root.value)) {
swal({title:"_(Invalid email address)_",text:"_(Please enter a valid sending email address)_",type:"error",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
return true;
}
function tls(form) {
form.TLSCert.disabled = form.UseTLSCert.selectedIndex==0;
}
function pwd(form) {
form.AuthUser.disabled = form.AuthMethod.selectedIndex==0;
form.AuthPass.disabled = form.AuthMethod.selectedIndex==0;
}
function mailtest() {
document.getElementById('testcounter').innerHTML = '('+counter+' sec)';
counter--;
if (counter>0) pid=setTimeout(mailtest,1000);
}
function disableTest() {
document.getElementById('testbutton').disabled = true;
}
function settings(form, data) {
var item = data.split(':');
form.server.value = item[0];
form.port.value = item[1];
form.UseTLS.value = item[2];
form.UseSTARTTLS.value = item[3];
form.AuthMethod.value = item[4];
disableTest();
}
</script>
<form markdown="1" name="smtp_setup" method="POST" action="/update.php" target="progressFrame" onsubmit="return mailcheck(this)" onchange="disableTest()">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg">
<input type="hidden" name="#section" value="ssmtp">
<input type="hidden" name="#include" value="/webGui/include/update.ssmtp.php">
<input type="hidden" name="#command" value="/webGui/scripts/notify">
<input type="hidden" name="#arg[1]" value="smtp-init">
_(Preset service)_:
: <select name="service" size="1" onchange="settings(this.form,this.value)">
<?=mk_option(_var($ssmtp,'service'), "smtp.gmail.com:465:YES:NO:login", "Gmail")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.gmail.com:587:YES:YES:login", "Gmail with TLS")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.office365.com:587:YES:YES:login", "Outlook")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.office365.com:587:YES:YES:login", "Hotmail")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.office365.com:587:YES:YES:login", "Office365")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.mail.yahoo.com:465:YES:NO:login", "Yahoo")?>
<?=mk_option(_var($ssmtp,'service'), "plus.smtp.mail.yahoo.com:465:YES:NO:login", "Yahoo Plus")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.mail.yahoo.co.uk:465:YES:NO:login", "Yahoo UK")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.mail.yahoo.com.au:465:YES:NO:login", "Yahoo AU/NZ")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.o2.ie:25:NO:NO:login", "O2")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.o2.co.uk:25:NO:NO:login", "O2 UK")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.o2online.de:25:NO:NO:login", "O2 Online Deutschland")?>
<?=mk_option(_var($ssmtp,'service'), "securesmtp.t-online.de:587:YES:YES:login", "T-Online Deutschland")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.1and1.com:587:YES:YES:login", "1&1")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.1und1.de:587:YES:YES:login", "1&1 Deutschland")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.att.yahoo.com:465:YES:NO:login", "AT&T")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.ntlworld.com:465:YES:NO:login", "NTL")?>
<?=mk_option(_var($ssmtp,'service'), "mail.btopenworld.com:25:NO:NO:login", "BT Openworld")?>
<?=mk_option(_var($ssmtp,'service'), "mail.btinternet.com:25:NO:NO:login", "BT Internet")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.comcast.net:465:YES:NO:login", "Comcast")?>
<?=mk_option(_var($ssmtp,'service'), "outgoing.verizon.net:465:YES:NO:login", "Verizon")?>
<?=mk_option(_var($ssmtp,'service'), "outgoing.yahoo.verizon.net:587:NO:NO:login", "Verizon (Yahoo hosted)")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.mail.com:465:YES:NO:login", "Mail.com")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.gmx.com:465:YES:NO:login", "GMX.com")?>
<?=mk_option(_var($ssmtp,'service'), "smtp.zoho.com:465:YES:NO:login", "zoho Mail")?>
<?=mk_option(_var($ssmtp,'service'), "::NO:NO:none", _("Custom"))?>
</select>
:smtp_preset_service_help:
_(Sending email address)_:
: <input type="text" name="root" value="<?=htmlspecialchars(_var($ssmtp,'root'))?>">
:smtp_email_address_help:
_(Email recipients)_:
: <input type="text" name="RcptTo" value="<?=htmlspecialchars(_var($ssmtp,'RcptTo'))?>">
:smtp_recipients_help:
_(Priority in header)_:
: <select name="SetEmailPriority">
<?=mk_option(_var($ssmtp,'SetEmailPriority'), "False", _("No"))?>
<?=mk_option(_var($ssmtp,'SetEmailPriority'), "True", _("Yes"))?>
</select>
:smtp_priority_help:
_(Email subject prefix)_:
: <input type="text" name="Subject" value="<?=htmlspecialchars(_var($ssmtp,'Subject'))?>">
:smtp_subject_prefix_help:
_(Mail server)_:
: <input type="text" name="server" value="<?=htmlspecialchars(_var($ssmtp,'server'))?>">
:smtp_mail_server_help:
_(Mail server port)_:
: <input type="text" name="port" class="narrow" maxlength="5" value="<?=htmlspecialchars(_var($ssmtp,'port'))?>">
:smtp_mail_server_port_help:
_(Use SSL/TLS)_:
: <select name="UseTLS">
<?=mk_option(_var($ssmtp,'UseTLS'), "NO", _("No"))?>
<?=mk_option(_var($ssmtp,'UseTLS'), "YES", _("Yes"))?>
</select>
:smtp_use_ssl_tls_help:
_(Use STARTTLS)_:
: <select name="UseSTARTTLS">
<?=mk_option(_var($ssmtp,'UseSTARTTLS'), "NO", _("No"))?>
<?=mk_option(_var($ssmtp,'UseSTARTTLS'), "YES", _("Yes"))?>
</select>
:smtp_use_starttls_help:
_(Define a TLS certificate)_:
: <select name="UseTLSCert" onchange="tls(this.form)">
<?=mk_option(_var($ssmtp,'UseTLSCert'), "NO", _("No"))?>
<?=mk_option(_var($ssmtp,'UseTLSCert'), "YES", _("Yes"))?>
</select>
:smtp_define_tls_cert_help:
_(TLS certificate location)_:
: <input type="text" name="TLSCert" value="<?=htmlspecialchars(_var($ssmtp,'TLSCert'))?>">
:smtp_tls_cert_location_help:
_(Authentication method)_:
: <select name="AuthMethod" onchange="pwd(this.form)">
<?=mk_option(_var($ssmtp,'AuthMethod'), "none", _("None"))?>
<?=mk_option(_var($ssmtp,'AuthMethod'), "cram-md5", _("CRAM-MD5"))?>
<?=mk_option(_var($ssmtp,'AuthMethod'), "login", _("Login"))?>
</select>
:smtp_authentication_method_help:
_(Username)_:
: <input type="text" name="AuthUser" value="<?=htmlspecialchars(_var($ssmtp,'AuthUser'))?>">
_(Password)_:
: <input type="password" name="AuthPass" value="<?=htmlspecialchars(_var($ssmtp,'AuthPass'))?>">
:smtp_username_password_help:
&nbsp;
: <input type="submit" name="#apply" value="_(Apply)_" disabled><input type="button" value="_(Done)_" onclick="done()">
<span id="testresult"><input type="button" id="testbutton" value="_(Test)_"<?if ($incomplete):?> disabled<?endif;?>></span>
</form>
+90
View File
@@ -0,0 +1,90 @@
Menu="UNRAID-OS"
Title="System Devices"
Icon="icon-hardware"
Tag="server"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
table.pre{margin-top:0;background:transparent}
table.pre td:first-child{width:144px}
table tr td{padding:0 0 3px 0;margin:0}
table tr td.thin{line-height:8px;height:8px}
</style>
<script>
$(function(){
$('#t1').load('/webGui/include/SysDevs.php',{table:'t1'});
$('#t2').load('/webGui/include/SysDevs.php',{table:'t2'});
$('#t3').load('/webGui/include/SysDevs.php',{table:'t3'});
$('#t4').load('/webGui/include/SysDevs.php',{table:'t4'});
});
function applyCfg() {
var message = "_(System Devices)_: _(A reboot is required to apply changes)_";
var string = "BIND=";
var elements = document.getElementById("vfiopci").elements;
for (var i = 0, element; element = elements[i++];) {
if (element.type === "checkbox" && element.checked === true)
string = string + element.value + " ";
}
string = string.trim();
if (string === "BIND=") {
string = "";
}
$.get( "/plugins/dynamix/include/update.vfio-pci-cfg.php", { cfg: string } )
.done(function(d) {
if (d==1) {
addRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(ALERT)_: _(Changes saved)_. _(Reboot to take effect)_.</b>";
} else {
removeRebootNotice(message);
document.getElementById("warning").innerHTML = "<b>_(No changes)_.</b>";
}
$("#applycfg").attr("disabled",true);
});
}
</script>
<?exec('ls /sys/kernel/iommu_groups/',$groups); ?>
<?if (count($groups) > 0):?>
**_(PCI Devices and IOMMU Groups)_**
<?else:?>
**_(PCI Devices (No IOMMU Groups Available))_**
<?endif;?>
:sysdevs_iommu_groups_help:
<?if (strpos(file_get_contents('/proc/cmdline'), 'pcie_acs_override=') !== false):?>
<p class="notice" style="line-height:30px;height:auto">_(Warning)_: _(Your system has booted with the PCIe ACS Override setting enabled)_. _(The below list doesn't not reflect the way IOMMU would naturally group devices)_.<br>
<?=my_hyperlink(_("To see natural IOMMU groups for your hardware, go to the [VM Manager] page and set the **PCIe ACS override** setting to **Disabled**"),'/Settings/VMSettings')?>.</p>
<?endif;?>
<pre><form id="vfiopci" class="js-confirm-leave" onsubmit="return false"><table id='t1' class='pre'><tr><td><div class="spinner"></div></td></tr></table></form></pre><br>
**_(CPU Thread Pairings)_**
:sysdevs_thread_pairings_help:
<pre><table id='t2' class='pre'><tr><td><div class="spinner"></div></td></tr></table></pre><br>
**_(USB Devices)_**
:sysdevs_usb_devices_help:
<pre><table id='t3' class='pre'><tr><td><div class="spinner"></div></td></tr></table></pre><br>
**_(SCSI Devices)_**
:sysdevs_scsi_devices_help:
<pre><table id='t4' class='pre'><tr><td><div class="spinner"></div></td></tr></table></pre>
<input type="button" value="_(Done)_" onclick="done()">
+239
View File
@@ -0,0 +1,239 @@
Menu="Flash"
Title="Syslinux Configuration"
Tag="edit"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$top = $themes1 ? -58 : -44;
function strip($area) {
return preg_replace(["/^|(\n) /","/\n$/"],["$1",""],$area);
}
$file = '/boot/syslinux/syslinux.cfg';
$current = @file_get_contents($file);
$default = @file_get_contents("$file-") ?: $current;
$current = preg_replace(["/\r\n/","/\r/","/\n$/"],["\n","\n",""],$current);
$default = preg_replace(["/\r\n/","/\r/","/\n$/"],["\n","\n",""],$default);
$title = _('Global Configuration');
$menu = 'menu default';
$mark = 'label ';
?>
<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
<style>
div.basic{display:block}
div.advanced{display:none}
textarea.raw{resize:none;font-family:bitstream;width:65.5%}
<?
switch (strtok($display['theme'],'-')) {
case 'gray':
case 'azure':
echo "span.array,span.system{margin-left:33.33%;width:65.5%;padding:2px 10px;font-weight:bold;border:solid 1px #606E7F;border-bottom:none}\n";
echo "textarea.menu{margin-left:33.33%;width:65.5%;margin-bottom:12px;padding:4px 10px;font-family:bitstream;border-top:none}\n";
break;
case 'white':
echo "span.array,span.system{margin-left:33.33%;width:65.5%;padding:2px 10px;font-weight:bold;border:solid 1px #1c1c1c;border-bottom:none}\n";
echo "textarea.menu{margin-left:33.33%;width:65.5%;margin-bottom:12px;padding:4px 10px;font-family:bitstream;border:1px solid #1c1b1b;border-top:none}\n";
break;
case 'black':
echo "span.array,span.system{margin-left:33.33%;width:65.5%;padding:2px 10px;font-weight:bold;border:solid 1px #f2f2f2;border-bottom:none}\n";
echo "textarea.menu{margin-left:33.33%;width:65.5%;margin-bottom:12px;padding:4px 10px;font-family:bitstream;border:1px solid #f2f2f2;border-top:none}\n";
break;
}
?>
</style>
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
<script>
const title = '<?=$title?>';
const menu = '<?=$menu?>';
const mark = '<?=$mark?>';
Array.prototype.indent = function(o) {
if (o) for (var i=0; i < this.length; i++) this[i] = ' '+this[i];
return this;
};
Array.prototype.spliceArray = function(i,n,a) {
return Array.prototype.splice.apply(this,[i,n].concat(a));
};
function prepareMenu(form) {
$('input[name="#arg[1]"]').val(form.boot.checked?1:0);
if ($('div.basic').is(':visible')) {
var label = [], area = [];
$(form).find('span[id^=label]').each(function(){
label.push($(this).text());
});
$(form).find('textarea.menu').each(function(i){
var start = $('#input-'+i).prop('checked') ? menu+'\n' : '';
area.push(start+$(this).val());
});
var text = [];
for (var i=0; i < label.length; i++) {
if (i==0) {
text.push(area[i]);
} else {
text.push(mark+label[i]);
text.push(area[i].replace(/^|(\n)/g,'$1 '));
}
}
// menu view
form.text.value = text.join('\n')+'\n';
} else {
// raw view
form.text.value = form.raw.value+'\n';
}
form.raw.disabled = true;
}
function setDefault(form) {
var text = <?=json_encode(array_map('strip',explode($mark,$default)))?>;
$(form).find('textarea.menu').each(function(i){
if (i < text.length) {
var area = text[i].split('\n');
var label = (i) ? area.shift():title;
var start = (area[0]==menu);
var checked = start ? ' checked':'';
if (i) label += "<span style='float:right'><input type='radio' id='input-"+i+"' title='<?=_('Set default boot menu')?>' onchange='changeMenu(this.form,this.id,true)'"+checked+"></span>";
$('#label-'+i).html(label).prop('class',start ? 'array':'system');
if (start) area.shift();
$(this).val(area.join('\n')).prop('rows',area.length).trigger('change');
} else {
$('#label-'+i).remove();
$(this).remove();
}
});
$(form).find('textarea.raw').val(<?=json_encode($default)?>).prop('rows',$(this).val().match(/\n/g).length+1).trigger('change');
}
function changeMenu(form,id,update) {
$(form).find('input.menu').each(function(){
// highlight default boot menu
var i = $(this).prop('id');
var label = $('#'+i.replace('input','label'));
if (i == id) {
label.prop('class','array');
$(this).prop('checked',true);
} else {
label.prop('class','system');
$(this).prop('checked',false);
}
});
if (update) {
// menu view -> update raw view
var n = 0, o = null;
var x = id.split('-')[1];
var text = form.raw.value.split('\n');
for (var i=0; i < text.length; i++) {
if (text[i].indexOf(mark) >= 0) if (++n == x) o = i + 1;
if (text[i].indexOf(menu) >= 0) text.splice(i,1);
}
if (o) text.splice(o,0,' '+menu);
$(form).find('textarea.raw').val(text.join('\n')).prop('rows',text.length);
}
}
$(function(){
$('form').find('textarea').each(function(){$(this).on('input change',function(event){
$(this).prop('rows',($(this).val().match(/\n/g)||[]).length+1);
if (event.type == 'input') return;
// propogate changes to 'other' view mode
var form = $(this).closest('form');
if ($(this).prop('class')=='menu') {
// menu view -> update raw view
var n = 0, o = 0, x = null;
var id = $(this).prop('id').split('-')[1];
var area = $(this).val().split('\n');
var raw = form.find('textarea.raw');
var text = raw.val().split('\n');
for (var i=0; i < text.length; i++) {
if (text[i].indexOf(mark) >= 0) {
if (n++ == id) x = i; else o = i + 1;
}
if (text[i].indexOf(menu) >= 0) o++;
if (x) break;
}
text.spliceArray(o,(x||text.length)-o,area.indent(o));
raw.val(text.join('\n')).prop('rows',text.length);
} else {
// raw view -> update menu view
var n = 0, id = null, area = [];
var text = $(this).val().split('\n');
for (var i=0; i < text.length; i++) {
if (text[i].indexOf(mark) >= 0) {
$('#menu-'+(n++)).val(area.join('\n')).prop('rows',area.length);
var label = $('#label-'+n);
label.html(label.html().replace(/^.*(<span.*)/,text[i].replace(mark,'')+'$1'));
area = [];
} else {
if (text[i].indexOf(menu) >= 0) id = 'input-'+n; else if (text[i].length) area.push(text[i].replace(/^ /,''));
}
}
$('#menu-'+n).val(area.join('\n')).prop('rows',area.length);
if (id) changeMenu(form,id,false);
}
});});
if ($.cookie('syslinux_viewmode')=='advanced') {
$('.advanced').show();
$('.basic').hide();
}
$('.advancedview').switchButton({
labels_placement: 'left',
off_label: "_(Menu View)_",
on_label: "_(Raw View)_",
checked: $.cookie('syslinux_viewmode')=='advanced'
});
$('.advancedview').change(function() {
$('.advanced').toggle('slow');
$('.basic').toggle('slow');
$.cookie('syslinux_viewmode', $('.advancedview').is(':checked') ? 'advanced':'basic', {expires:3650});
});
});
</script>
<span class="status" style="margin-top:<?=$top?>px"><input type="checkbox" class="advancedview"></span>
:syslinux_cfg_help:
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareMenu(this)">
<input type="hidden" name="#include" value="/webGui/include/update.file.php">
<input type="hidden" name="#file" value="<?=$file;?>">
<input type="hidden" name="#command" value="/webGui/scripts/bootmode">
<input type="hidden" name="#arg[1]" value="">
<input type="hidden" name="text" value="">
<div markdown="1" class="basic">
_(Syslinux configuration)_:
: <?$i=0;
foreach (array_map('strip',explode($mark,$current)) as $area):
$area = explode("\n", $area);
$label = ($i) ? array_shift($area):$title;
$start = in_array($menu,$area);
if ($start) unset($area[array_search($menu,$area)]);
?><span id="label-<?=$i?>" class="<?=$start?'array':'system'?>"><?=$label?>
<?if ($i):?><span style="float:right"><input type="radio" id="input-<?=$i?>" class="menu" <?=$start?'checked':''?> title="_(Set default boot menu)_" onchange="changeMenu(this.form,this.id,true)"></span><?endif;?></span>
<textarea class="menu" id="menu-<?=$i++?>" spellcheck="false" cols="80" rows="<?=count($area)?>" maxlength="2048"><?=implode("\n",$area)?></textarea>
<?endforeach;?>
</div>
<div markdown="1" class="advanced">
_(Syslinux configuration)_:
: <textarea class="raw" name="raw" spellcheck="false" cols="80" rows="<?=substr_count($current,"\n")+1?>" maxlength="2048"><?=$current?></textarea>
</div>
_(Server boot mode)_:
: <?=is_dir('/sys/firmware/efi') ? 'UEFI' : 'Legacy'?>
_(Permit UEFI boot mode)_ <input type="checkbox" name="boot" <?=is_dir('/boot/EFI')?'checked':''?>>
: *_(Boot system in UEFI mode)_. _(Please check your system settings to support UEFI boot mode)_.*
<input type="button" value="_(Default)_" onclick="setDefault(this.form)">
: <input type="submit" value="_(Apply)_"><input type="button" value="_(Done)_" onclick="done()">
:syslinux_button_help:
</form>
+118
View File
@@ -0,0 +1,118 @@
Menu="UNRAID-OS"
Title="System Log"
Icon="icon-log"
Tag="list"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
$log = '/var/log/syslog';
$cfg = '/boot/config/rsyslog.cfg';
$max = 5000;
$select = [];
if (file_exists($cfg)) {
$syslog = parse_ini_file($cfg);
if (isset($syslog['local_server']) && isset($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
natsort($logs);
$select[] = "<select onchange='showLog(this.value)'>";
$select[] = mk_option(1,$log,'syslog');
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
$select[] = "</select>";
}
}
$select = implode($select);
?>
<style>
input#max{border:none;width:60px;margin:0;padding:0}
</style>
<script>
var logfile = "<?=$log?>";
function zipfile(){
var d = new Date();
return "<?=$zip?>-"+logfile.split('/').reverse()[0].replace('.log','')+'-'+d.toISOString().substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
}
function cleanUp(file) {
if (document.hasFocus()) {
$('input#download').val("_(Download)_").prop('disabled',false);
$.post('/webGui/include/Download.php',{cmd:'delete',file:file});
} else {
setTimeout(function(){cleanUp(file);},2000);
}
}
function syslog(file) {
$('input#download').val("_(Downloading)_...").prop('disabled',true);
$.post('/webGui/include/Download.php',{cmd:'save',source:logfile,file:file},function(zip) {
location = zip;
setTimeout(function(){cleanUp(file);},4000);
});
}
function highlight(checked,line) {
var o = checked ? '-' : '';
var n = ($('span.text').css('display')=='none' && !checked) ? 'none' : '';
switch (line) {
case 'E': $('span.'+o+'error').css('display',n); $('span.error'+o).toggleClass('error -error error-'); break;
case 'W': $('span.'+o+'warn').css('display',n); $('span.warn'+o).toggleClass('warn -warn warn-'); break;
case 'S': $('span.'+o+'system').css('display',n); $('span.system'+o).toggleClass('system -system system-'); break;
case 'A': $('span.'+o+'array').css('display',n); $('span.array'+o).toggleClass('array -array array-'); break;
case 'L': $('span.'+o+'login').css('display',n); $('span.login'+o).toggleClass('login -login login-'); break;
case 'N': $('span.text,span[class^="-"]').css('display',checked ? 'none':''); break;
}
$('span.label').show();
}
function toggle(checked) {
highlight(checked,'E');
highlight(checked,'W');
highlight(checked,'S');
highlight(checked,'A');
highlight(checked,'L');
$('span.label input[type=checkbox]').not('.ctrl').prop('checked',checked);
}
<?if (_var($display,'resize')):?>
function resize() {
$('pre.up').height(Math.max(window.innerHeight-320,330));
}
<?endif;?>
function showLog(log) {
logfile = log;
$('span.label input[type=checkbox]').prop('checked',true);
$('span.label').each(function(){
var type = $(this).attr('class').replace('label','').replace(/-/g,'');
$(this).removeClass().addClass(type+' label');
});
timers.syslog = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
$.post('/webGui/include/Syslog.php',{log:log,max:$('#max').val()||<?=$max?>},function(data){
clearTimeout(timers.syslog);
$('pre.up').html(data);
$('div.spinner.fixed').hide('slow');
});
}
$(function() {
$('input#max').on('keydown',function(e) {
if (e.keyCode === 13) {
e.preventDefault();
e.stopImmediatePropagation();
showLog(logfile);
}
});
<?if (_var($display,'resize')):?>
resize();
$(window).bind('resize',function(){resize();});
<?endif;?>
showLog(logfile);
});
$('.tabs').append("<span class='status'><span class='lite label'>_(Log size)_:&nbsp;&nbsp;<input type='number' id='max' value='' placeholder='<?=$max?>'></span><?=$select?><span class='lite label'><label>_(Text)_<input type='checkbox' class='ctrl' onclick='highlight(!this.checked,\"N\")' checked></label></span><span class='error label'><label>_(Error)_<input type='checkbox' onclick='highlight(this.checked,\"E\")' checked></label></span><span class='warn label'><label>_(Warning)_<input type='checkbox' onclick='highlight(this.checked,\"W\")' checked></label></span><span class='system label'><label>_(System)_<input type='checkbox' onclick='highlight(this.checked,\"S\")' checked></label></span><span class='array label'><label>_(Array)_<input type='checkbox' onclick='highlight(this.checked,\"A\")' checked></label></span><span class='login label'><label>_(Login)_<input type='checkbox' onclick='highlight(this.checked,\"L\")' checked></label></span><span class='lite label'><input type='checkbox' class='ctrl' onclick='toggle(this.checked)' checked></span></span>");
</script>
<pre class='up'></pre>
<input type="button" id="download" value="_(Download)_" onclick="syslog(zipfile())"><input type="button" value="_(Refresh)_" onclick="showLog(logfile)"><input type="button" value="_(Done)_" onclick="done()">
+171
View File
@@ -0,0 +1,171 @@
Menu="NetworkServices"
Title="Syslog Server"
Icon="icon-eula"
Tag="file-text-o"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$syslog = @parse_ini_file('/boot/config/rsyslog.cfg') ?: [];
function plain($ip) {
return str_replace(['[',']'],'',$ip);
}
// Get ports in use
$portsInUse = [];
exec("lsof -Pni|awk '/LISTEN/ && \$9!~/127.0.0.1/ && \$9!~/\\[::1\\]/{print \$9}'|sort -u", $output);
$ethX = 'eth0';
$addr = ipaddr($ethX);
$bind = _var($var,'BIND_MGT')=='yes';
$list = ['*',$addr];
foreach ($output as $line) {
[$ip, $port] = my_explode(':', $line);
if (!in_array($port,$portsInUse) && (!$bind || in_array(plain($ip),$list))) $portsInUse[] = $port;
}
?>
<style>
span.span{display:inline-block;width:224px}
</style>
<script>
function localFolder(local,time) {
if (local) $('#local_folder').show(time); else $('#local_folder').hide(time);
}
function logOptions(log,time) {
if (log) $('#log_options').show(time); else $('#log_options').hide(time);
}
$(function(){
localFolder(document.syslog.local_server.value);
logOptions(document.syslog.log_rotation.value);
});
function validatePort(form) {
var portsInUse = JSON.parse('<?=json_encode($portsInUse)?>');
var currentPort = "<?=(_var($syslog,'local_server') && _var($syslog,'server_protocol')!='udp') ? _var($syslog,'server_port',514) : 514?>";
var port = $(form).find('input[name="server_port"]');
var remotePort = $(form).find('input[name="remote_port"]');
var protocol = $(form).find('select[name="server_protocol"]').val();
if ( !port.val() ) port.val("514");
port.val(parseInt(port.val()));
remotePort.val(parseInt(remotePort.val()));
var newport = port.val();
if (newport != currentPort && protocol != "udp" && $(form).find('select[name="local_server"]').val()) {
if (portsInUse.includes(newport)) {
swal({title:'_(Port already in use)_',text:sprintf('_(Port %s is already in use by other services)_',newport),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return;
}
}
var list = [];
if (newport < 1 || newport > 65535) {
list.push("_(Local syslog port)_");
}
var remote = remotePort.val();
if (!remote) remote = 514;
if (remote < 1 || remote > 65535) {
list.push("_(Remote syslog port)_");
}
if (list.length > 0) {
swal({title:'_(Port out of range)_',text:sprintf('_(%s is out of range (minimum 1 maximum 65535))_',list.join(", ")),type:'error',showCancelButton:false,confirmButtonText:"_(OK)_"});
return;
}
form.submit();
}
</script>
<form markdown="1" name="syslog" method="POST" action="/update.php" target="progressFrame">
<input type="hidden" name="#file" value="/boot/config/rsyslog.cfg">
<input type="hidden" name="#command" value="/webGui/scripts/rsyslog_config">
_(Local syslog server)_:
: <span class="span"><select name="local_server" onchange="localFolder(this.value,'slow')">
<?=mk_option(_var($syslog,'local_server'), "", _("Disabled"))?>
<?=mk_option(_var($syslog,'local_server'), "1", _("Enabled"))?>
</select></span>
<select name="server_protocol" class="narrow">
<?=mk_option(_var($syslog,'server_protocol'), "udp", _("UDP"))?>
<?=mk_option(_var($syslog,'server_protocol'), "tcp", _("TCP"))?>
<?=mk_option(_var($syslog,'server_protocol'), "both", _("Both"))?>
</select>
<input type="text" name="server_port" class="trim" value="<?=_var($syslog,'server_port')?>" maxlength="5" placeholder="514">
:syslog_local_server_help:
<div markdown="1" id="local_folder" style="display:none">
_(Local syslog folder)_:
: <select name="server_folder">
<?=mk_option(0,'','&lt;'._('custom').'&gt;','disabled')?>
<?foreach ($shares as $share){echo mk_option(_var($syslog,'server_folder'), '/mnt/user/'.$share['name'], $share['name']);}?>
</select>
:syslog_local_folder_help:
_(Local syslog rotation)_:
: <select name="log_rotation" onchange="logOptions(this.value,'slow')">
<?=mk_option(_var($syslog,'log_rotation'), "", _("Disabled"))?>
<?=mk_option(_var($syslog,'log_rotation'), "1", _("Enabled"))?>
</select>
:syslog_local_rotation_help:
<div markdown="1" id="log_options" style="display:none">
_(Local syslog maximum file size)_:
: <select name="log_size">
<?=mk_option(_var($syslog,'log_size'), '1M', '1 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '2M', '2 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '5M', '5 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '10M', '10 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '20M', '20 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '50M', '50 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '100M', '100 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '200M', '200 '._('MB'))?>
<?=mk_option(_var($syslog,'log_size'), '500M', '500 '._('MB'))?>
</select>
:syslog_local_file_size_help:
_(Local syslog number of files)_:
: <select name="log_files">
<?=mk_option(_var($syslog,'log_files'), '1', '1')?>
<?=mk_option(_var($syslog,'log_files'), '2', '2')?>
<?=mk_option(_var($syslog,'log_files'), '3', '3')?>
<?=mk_option(_var($syslog,'log_files'), '4', '4')?>
</select>
:syslog_local_file_number_help:
</div>
</div>
_(Remote syslog server)_:
: <span class="span"><input type="text" name="remote_server" class="narrow" value="<?=_var($syslog,'remote_server')?>" maxlength="23" placeholder="_(name or ip address)_"></span>
<select name="remote_protocol" class="narrow" size="1">
<?=mk_option(_var($syslog,'remote_protocol'), "udp", _("UDP"))?>
<?=mk_option(_var($syslog,'remote_protocol'), "tcp", _("TCP"))?>
</select>
<input type="number" name="remote_port" class="trim" value="<?=_var($syslog,'remote_port')?>" maxlength="5" placeholder="514" pattern="([0-9]{1,5})">
:syslog_remote_server_help:
_(Mirror syslog to flash)_:
: <select name="syslog_flash" size="1">
<?=mk_option(_var($syslog,'syslog_flash'), "", _("No"))?>
<?=mk_option(_var($syslog,'syslog_flash'), "1", _("Yes"))?>
</select>
:syslog_mirror_flash_help:
&nbsp;
: <input type="button" value="_(Apply)_" onclick='validatePort(this.form)' disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
@@ -0,0 +1,23 @@
Menu="Buttons:3"
Title="Terminal"
Icon="icon-u-terminal"
Code="e93f"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<script>
function TerminalButton() {
var d = new Date();
openTerminal('ttyd','Web Terminal '+d.getTime(),'');
}
</script>
+4
View File
@@ -0,0 +1,4 @@
Menu="Tasks:90"
Type="xmenu"
Tabs="false"
Code="e909"
+127
View File
@@ -0,0 +1,127 @@
Menu="Scheduler"
Title="TRIM Settings"
Tag="superpowers"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$mode = ['Disabled','Hourly','Daily','Weekly','Monthly'];
$days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
?>
<script>
function trimNow() {
openPlugin("ssd_trim", "_(Perform TRIM Operation)_");
}
function presetTrim(form) {
var mode = form.mode.value;
form.min.disabled = mode==0;
form.day.disabled = mode==0 || mode!=3;
form.dotm.disabled = mode==0 || mode!=4;
form.hour1.disabled = mode==0;
form.hour2.disabled = mode==0;
form.day.value = form.day.disabled ? '*' : (form.day.value=='*' ? 0 : form.day.value);
form.dotm.value = form.dotm.disabled ? '*' : (form.dotm.value=='*' ? 1 : form.dotm.value);
if (mode==1) {$('#hour1').hide(); $('#hour2').show();} else {$('#hour2').hide(); $('#hour1').show();}
}
function prepareTrim(form) {
var include = [];
var mode = form.mode.value;
form.hour.value = mode!=1 ? form.hour1.value : form.hour2.value;
form.min.value = mode!=1 ? form.min.value : 0;
form.hour1.disabled = true;
form.hour2.disabled = true;
for (var i=0,item; item=form.disk.options[i]; i++) {
if (item.selected) {
include.push(item.value);
item.selected = false;
}
}
item = form.disk.options[0];
item.value = include.join(',');
item.selected = true;
}
$(function() {
presetTrim(document.trim_schedule);
});
</script>
<form markdown="1" name="trim_schedule" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareTrim(this)">
<input type="hidden" name="#file" value="dynamix/dynamix.cfg">
<input type="hidden" name="#section" value="ssd">
<input type="hidden" name="#include" value="/webGui/include/update.trim.php">
<input type="hidden" name="hour" value="">
_(TRIM schedule)_:
: <select name="mode" onchange="presetTrim(this.form)">
<?for ($m=0; $m<count($mode); $m++):?>
<?=mk_option(_var($ssd,'mode'), strval($m), _($mode[$m]))?>
<?endfor;?>
</select>
:trim_schedule_plug:
> Choose a trim schedule ranging from hourly, daily, weekly and monthly.
>
> The interval determines how often SSD trim will run, it runs in the background.
:end
_(Day of the week)_:
: <select name="day">
<?for ($d=0; $d<count($days); $d++):?>
<?=mk_option(_var($ssd,'day'), strval($d), _($days[$d],0))?>
<?endfor;?>
<?=mk_option(_var($ssd,'day'), "*", "--------", _("disabled"))?>
</select>
:trim_day_of_the_week_plug:
> Choose a day when the weekly schedule is selected. Otherwise disabled.
:end
_(Day of the month)_:
: <select name="dotm">
<?for ($d=1; $d<=31; $d++):?>
<?=mk_option(_var($ssd,'dotm'), strval($d), sprintf("%02d", $d))?>
<?endfor;?>
<?=mk_option(_var($ssd,'dotm'), "*", "--------", _("disabled"))?>
</select>
:trim_day_of_the_month_plug:
> Choose a date when the monthly schedule is selected. Otherwise disabled.
:end
_(Time of the day)_:
: <span id="hour1" style="display:none"><select name="hour1" class="narrow">
<?for ($d=0; $d<=23; $d++):?>
<?=mk_option(_var($ssd,'hour'), strval($d), sprintf("%02d", $d))?>
<?endfor;?>
</select>
<select name="min" class="narrow">
<?for ($d=0; $d<=55; $d+=5):?>
<?=mk_option(_var($ssd,'min'), strval($d), sprintf("%02d", $d))?>
<?endfor;?>
</select>&nbsp;&nbsp;_(HH:MM)_</span>
: <span id="hour2" style="display:none"><select name="hour2">
<?=mk_option(_var($ssd,'hour'), "*/1", _("Every hour"))?>
<?=mk_option(_var($ssd,'hour'), "*/2", _("Every 2 hours"))?>
<?=mk_option(_var($ssd,'hour'), "*/3", _("Every 3 hours"))?>
<?=mk_option(_var($ssd,'hour'), "*/4", _("Every 4 hours"))?>
<?=mk_option(_var($ssd,'hour'), "*/6", _("Every 6 hours"))?>
<?=mk_option(_var($ssd,'hour'), "*/8", _("Every 8 hours"))?>
</select></span>
:trim_time_of_the_day_plug:
> When an hourly schedule is selected this will set the interval in hours. An interval always starts on the whole hour (minute 0).
>
> For the other schedules choose here the time of the day trim should start.
:end
&nbsp;
: <input type="submit" name="#apply" value="_(Apply)_"><input type="button" value="_(Done)_" onclick="done()"><input type="button" value="_(Trim Now)_" onclick="trimNow()">
</form>
+4
View File
@@ -0,0 +1,4 @@
Menu="Tools:10"
Type="menu"
Title="Unraid OS"
Tag="lemon-o"
+191
View File
@@ -0,0 +1,191 @@
Menu="UserList"
Title="Add User"
Tag="user"
---
<?PHP
/* Copyright 2005-2020, Lime Technology
* Copyright 2012-2020, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$void = "<img src='/webGui/images/user.png' width='48' height='48' onclick='$(&quot;#drop&quot;).click()' style='cursor:pointer' title='"._('Click to select PNG file')."'>";
$icon = "<i class='fa fa-trash top' title='"._('Restore default image')."' onclick='restore()'></i>";
$zxcvbn = file_exists('/boot/config/plugins/dynamix/zxcvbn.js');
?>
<style>
<?if ($display['theme']=='gray'):?>
span#dropbox{border:1px solid #606E7F;border-radius:5px;background:#121510;padding:28px 12px;line-height:72px;margin-right:16px}
<?elseif ($display['theme']=='azure'):?>
span#dropbox{border:1px solid #606E7F;border-radius:5px;background:#EDEAEF;padding:28px 12px;line-height:72px;margin-right:16px}
<?elseif ($display['theme']=='black'):?>
span#dropbox{border:1px solid #f2f2f2;border-radius:5px;background:#262626;padding:28px 12px;line-height:72px;margin-right:16px}
<?else:?>
span#dropbox{border:1px solid #1c1c1c;border-radius:5px;background:#e8e8e8;padding:28px 12px;line-height:72px;margin-right:16px}
<?endif;?>
i.top{position:absolute;padding-top:4px;cursor:pointer}
i#showPass.checked{opacity:0.5}
.usage-disk.sys{display:inline-block;width:10rem;top:<?=$themes2?'1.2':'.2'?>rem;margin-left:12px;border-radius:4px}
</style>
<script src="<?autov('/webGui/javascript/jquery.filedrop.js')?>"></script>
<?if ($zxcvbn):?>
<script src="<?autov('/boot/config/plugins/dynamix/zxcvbn.js')?>" async></script>
<?endif;?>
<script>
var path = '/boot/config/plugins/dynamix/users';
var filename = '';
function base64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
function showPassword() {
if ($('#showPass').hasClass('checked')) {
$('#showPass').removeClass('checked fa-eye-slash').addClass('fa-eye');
var type = 'password';
} else {
$('#showPass').addClass('checked fa-eye-slash').removeClass('fa-eye');
var type = 'text';
}
$('input[name="userPasswordGUI"]').attr('type',type);
$('input[name="userPasswordConfGUI"]').attr('type',type);
}
function checkUsername(form) {
var username = form.userName.value.trim();
if (!username.match('^[a-z_][a-z0-9_-]*[$]?$')) {
$('input[name="cmdUserEdit"]').val("_(Add)_");
swal({title:"_(Invalid user name)_",text:"_(Use only lowercase letters, digits, underscores and dashes)_",type:"error",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
if (form.userPasswordGUI.value.length > 128 || form.userPasswordConfGUI.value.length > 128) {
swal({title:"_(Password too long)_",text:"_(Use a password up to 128 characters)_",type:"error",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
if (filename) {
$.post("/webGui/include/FileUpload.php",{cmd:'save',path:path,filename:filename,output:username+'.png'});
}
form.userPassword.value = base64(form.userPasswordGUI.value);
form.userPasswordConf.value = base64(form.userPasswordConfGUI.value);
form.userPasswordGUI.disabled = true;
form.userPasswordConfGUI.disabled = true;
return true;
}
function validatePassword(input) {
<?if ($zxcvbn):?>
var custom = ['unraid','limetech','lime-technology','bergware','squidly'];
var strength = ['Worst','Bad','Weak','Good','Strong'];
var emoji = ['&#128565;','&#128553;','&#128532;','&#128512;','&#128526;'];
if (!input) {
$('#strength-bar').css('background-color','transparent');
$('#strength-text').html('');
$('.usage-disk.sys').addClass('none');
} else {
var bar = zxcvbn(input,custom);
switch (bar.score) {
case 0: $('#strength-bar').css('background-color','red'); break;
case 1: $('#strength-bar').css('background-color','yellow'); break;
case 2: $('#strength-bar').css('background-color','orange'); break;
case 3: $('#strength-bar').css('background-color','blue'); break;
case 4: $('#strength-bar').css('background-color','green'); break;
}
$('#strength-bar').css('width',Math.min(input.length*100/64,100)+'%');
$('#strength-text').html(emoji[bar.score]+' '+strength[bar.score]+'. '+bar.feedback.warning);
$('.usage-disk.sys').removeClass('none');
}
<?endif;?>
}
function restore() {
// restore original image
$('#dropbox').html("<?=$void?>");
filename = '';
}
$(function(){
var dropbox = $('#dropbox');
// attach the drag-n-drop feature to the 'dropbox' element
dropbox.filedrop({
maxfiles:1,
maxfilesize:512, // KB
url:'/webGui/include/FileUpload.php',
data:{path:path,"csrf_token":"<?=$var['csrf_token']?>"},
beforeEach:function(file) {
if (!file.type.match(/^image\/png/)) {
swal({title:"Warning",text:"Only PNG images are allowed!",type:"warning",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
},
error: function(error, file, i) {
switch (error) {
case 'BrowserNotSupported':
swal({title:"_(Browser error)_",text:"_(Your browser does not support HTML5 file uploads)_!",type:"error",html:true,confirmButtonText:"_(Ok)_"});
break;
case 'TooManyFiles':
swal({title:"_(Too many files)_",text:"_(Please select one file only)_!",type:"error",html:true});
break;
case 'FileTooLarge':
swal({title:"_(File too large)_",text:"_(Maximum file upload size is 512K)_ (524,288 _(bytes)_)",type:"error",html:true,confirmButtonText:"_(Ok)_"});
break;
}
},
uploadStarted:function(i,file,count) {
var image = $('img', $(dropbox));
var reader = new FileReader();
image.width = 48;
image.height = 48;
reader.onload = function(e){image.attr('src',e.target.result);};
reader.readAsDataURL(file);
},
uploadFinished:function(i,file,response) {
if (response == 'OK 200') {
if (!filename) $(dropbox).append("<?=$icon?>");
$('input[name="userDesc"]').trigger('change');
filename = file.name;
} else {
swal({title:"_(Upload error)_",text:response,type:"error",html:true,confirmButtonText:"_(Ok)_"});
}
}
});
// simulate a drop action when manual file selection is done
$('#drop').bind('change', function(e) {
var files = e.target.files;
if ($('#dropbox').triggerHandler({type:'drop',dataTransfer:{files:files}})==false) e.stopImmediatePropagation();
});
});
</script>
<form markdown="1" name="user_edit" method="POST" action="/update.htm" target="progressFrame" onsubmit="return checkUsername(this)">
_(User name)_:
: <input type="text" name="userName" maxlength="40" onKeyUp="this.form.cmdUserEdit.disabled=(this.form.userName.value=='')">
:user_add_username_help:
_(Description)_:
: <input type="text" name="userDesc" maxlength="64" pattern='[^&:"]*'>
:user_add_description_help:
_(Custom image)_:
: <span id="dropbox"><?=$void?></span><em>_(Drag-n-drop a PNG file or click the image at the left)_</em><input type="file" id="drop" accept="image/png" style="display:none">
:user_add_custom_image_help:
_(Password)_:
<input type="hidden" name="userPassword" value="">
: <input type="password" name="userPasswordGUI" maxlength="129" autocomplete="new-password" onKeyUp="validatePassword(this.value);this.form.cmdUserEdit.disabled=(this.form.userName.value=='' || this.form.userPasswordGUI.value!=this.form.userPasswordConfGUI.value)">
<i id="showPass" class="fa fa-eye" style="cursor:pointer" title="_(Show / Hide password)_" onclick="showPassword()"></i><span><span class="usage-disk sys none"><span id="strength-bar" style="width:0"></span><span></span></span><span id="strength-text"></span></span>
:user_password_help:
_(Retype password)_:
<input type="hidden" name="userPasswordConf" value="">
: <input type="password" name="userPasswordConfGUI" maxlength="129" autocomplete="new-password" onKeyUp="this.form.cmdUserEdit.disabled=(this.form.userName.value=='' || this.form.userPasswordGUI.value!=this.form.userPasswordConfGUI.value)">
&nbsp;
: <input type="submit" name="cmdUserEdit" value="_(Add)_" onclick="this.value='Add'" disabled><input type="button" value="_(Done)_" onclick="done('UserAdd')">
</form>
+339
View File
@@ -0,0 +1,339 @@
Menu="UserList"
Title="Edit User"
Tag="user"
---
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?if (!array_key_exists($name, $users)):?>
<p class="notice"><?=sprintf(_('User %s has been deleted'),htmlspecialchars($name))?>.</p><br>
<input type="button" value="_(Done)_" onClick="done()">
<?return;?>
<?endif;?>
<?
$user = "/boot/config/plugins/dynamix/users/$name.png";
$void = "<img src='/webGui/images/user.png' width='48' height='48' id='image' onclick='$(&quot;#drop&quot;).click()' style='cursor:pointer' title='"._('Click to select PNG file')."'>";
$icon = "<i class='fa fa-trash top' title='"._('Restore default image')."' onclick='restore()'></i>";
$zxcvbn = file_exists('/boot/config/plugins/dynamix/zxcvbn.js');
$file = "/boot/config/ssh/root/authorized_keys";
$text = preg_replace(["/\r\n/","/\r/"],"\n", @file_get_contents($file) ?: '');
?>
<style>
<?if ($display['theme']=='gray'):?>
span#dropbox{border:1px solid #606E7F;border-radius:5px;background:#121510;padding:28px 12px;line-height:72px;margin-right:16px}
<?elseif ($display['theme']=='azure'):?>
span#dropbox{border:1px solid #606E7F;border-radius:5px;background:#EDEAEF;padding:28px 12px;line-height:72px;margin-right:16px}
<?elseif ($display['theme']=='black'):?>
span#dropbox{border:1px solid #f2f2f2;border-radius:5px;background:#262626;padding:28px 12px;line-height:72px;margin-right:16px}
<?else:?>
span#dropbox{border:1px solid #1c1c1c;border-radius:5px;background:#e8e8e8;padding:28px 12px;line-height:72px;margin-right:16px}
<?endif;?>
i.top{position:absolute;padding-top:4px;cursor:pointer}
i#showPass.checked{opacity:0.5}
.usage-disk.sys{display:inline-block;width:10rem;top:<?=$themes2?'1.2':'.2'?>rem;margin-left:12px;border-radius:4px}
</style>
<script src="<?autov('/webGui/javascript/jquery.filedrop.js')?>"></script>
<?if ($zxcvbn):?>
<script src="<?autov('/boot/config/plugins/dynamix/zxcvbn.js')?>" async></script>
<?endif;?>
<script>
var path = '/boot/config/plugins/dynamix/users';
var filename = '';
function base64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
function showPassword() {
if ($('#showPass').hasClass('checked')) {
$('#showPass').removeClass('checked fa-eye-slash').addClass('fa-eye');
var type = 'password';
} else {
$('#showPass').addClass('checked fa-eye-slash').removeClass('fa-eye');
var type = 'text';
}
$('input[name="userPasswordGUI"]').attr('type',type);
$('input[name="userPasswordConfGUI"]').attr('type',type);
}
function checkPassword(form) {
if (form.userPasswordGUI.value.length > 128 || form.userPasswordConfGUI.value.length > 128) {
swal({title:"_(Password too long)_",text:"_(Use a password up to 128 characters)_",type:"error",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
form.userPassword.value = base64(form.userPasswordGUI.value);
form.userPasswordConf.value = base64(form.userPasswordConfGUI.value);
form.userPasswordGUI.disabled = true;
form.userPasswordConfGUI.disabled = true;
return true;
}
function validatePassword(input) {
<?if ($zxcvbn):?>
var custom = ['unraid','limetech','lime-technology','bergware','squidly'];
var strength = ['Worst','Bad','Weak','Good','Strong'];
var emoji = ['&#128565;','&#128553;','&#128532;','&#128512;','&#128526;'];
if (!input) {
$('#strength-bar').css('background-color','transparent');
$('#strength-text').html('');
$('.usage-disk.sys').addClass('none');
} else {
var bar = zxcvbn(input,custom);
switch (bar.score) {
case 0: $('#strength-bar').css('background-color','red'); break;
case 1: $('#strength-bar').css('background-color','yellow'); break;
case 2: $('#strength-bar').css('background-color','orange'); break;
case 3: $('#strength-bar').css('background-color','blue'); break;
case 4: $('#strength-bar').css('background-color','green'); break;
}
$('#strength-bar').css('width',Math.min(input.length*100/64,100)+'%');
$('#strength-text').html(emoji[bar.score]+' '+strength[bar.score]+'. '+bar.feedback.warning);
$('.usage-disk.sys').removeClass('none');
}
<?endif;?>
}
function restore() {
// restore original image and activate APPLY button
$('#dropbox').html("<?=$void?>");
$('input[name="userDesc"]').trigger('change');
filename = 'reset';
}
function upload(remove) {
// save or delete upload when APPLY is pressed
if (remove || filename=='reset') {
$.post("/webGui/include/FileUpload.php",{cmd:'delete',path:path,filename:'<?=addslashes(htmlspecialchars($name))?>.png'});
} else if (filename) {
$.post("/webGui/include/FileUpload.php",{cmd:'save',path:path,filename:filename,output:'<?=addslashes(htmlspecialchars($name))?>.png'});
}
}
function checkKey(form) {
// check syntax of ssh keys
var rows = form.text.value.split('\n');
for (var i=0,row; row=rows[i]; i++) {
if (row.search(/^(ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$/)==-1) {
swal({title:"_(Invalid Key)_",text:"["+(i+1)+"] "+row.split(' ')[0]+": _(Syntax of the key is incorrect)_!",type:"error",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
}
return true;
}
$(function(){
var dropbox = $('#dropbox');
// attach the drag-n-drop feature to the 'dropbox' element
dropbox.filedrop({
maxfiles:1,
maxfilesize:512, // KB
url:'/webGui/include/FileUpload.php',
data:{"csrf_token":"<?=$var['csrf_token']?>"},
beforeEach:function(file) {
if (!file.type.match(/^image\/png/)) {
swal({title:"Warning",text:"_(Only PNG images are allowed)_!",type:"warning",html:true,confirmButtonText:"_(Ok)_"});
return false;
}
},
error: function(error, file, i) {
switch (error) {
case 'BrowserNotSupported':
swal({title:"_(Browser error)_",text:"_(Your browser does not support HTML5 file uploads)_!",type:"error",html:true,confirmButtonText:"_(Ok)_"});
break;
case 'TooManyFiles':
swal({title:"_(Too many files)_",text:"_(Please select one file only)_!",html:true,type:"error"});
break;
case 'FileTooLarge':
swal({title:"_(File too large)_",text:"_(Maximum file upload size is 512K)_ (524,288 _(bytes)_)",type:"error",html:true,confirmButtonText:"_(Ok)_"});
break;
}
},
uploadStarted:function(i,file,count) {
var image = $('img', $(dropbox));
var reader = new FileReader();
image.width = 48;
image.height = 48;
reader.onload = function(e){image.attr('src',e.target.result);};
reader.readAsDataURL(file);
},
uploadFinished:function(i,file,response) {
if (response == 'OK 200') {
if (!filename || filename=='reset') $(dropbox).append("<?=$icon?>");
$('input[name="userDesc"]').trigger('change');
filename = file.name;
} else {
swal({title:"_(Upload error)_",text:response,type:"error",html:true,confirmButtonText:"_(Ok)_"});
}
}
});
// simulate a drop action when manual file selection is done
$('#drop').bind('change', function(e) {
var files = e.target.files;
if ($('#dropbox').triggerHandler({type:'drop',dataTransfer:{files:files}})==false) e.stopImmediatePropagation();
});
// auto size the textarea
$('form').find('textarea').on('input change',function(){
$(this).prop('rows',Math.max(($(this).val().match(/\n/g)||[]).length+1,10));
$('form').find('input[value="_(Save)_"]').prop('disabled',false);
});
});
</script>
<div class="spinner fixed"></div>
<form markdown="1" method="POST" action="/update.htm" target="progressFrame" onsubmit="upload(<?=$name=="root" ? 'false' : 'this.confirmDelete.checked'?>)">
<input type="hidden" name="userName" value="<?=htmlspecialchars($name)?>">
_(User name)_:
: <?=htmlspecialchars($name)?>
_(Description)_:
: <input type="text" name="userDesc" maxlength="64" value="<?=htmlspecialchars($users[$name]['desc'])?>" pattern='[^&:"]*'>
:user_edit_description_help:
_(Custom image)_:
: <span id="dropbox">
<?if (file_exists($user)):?>
<img src="<?=autov($user)?>" id="image" width="48" height="48" onclick="$('#drop').click()" style="cursor:pointer" title="_(Click to select PNG file)_"><?=$icon?>
<?else:?>
<?=$void?>
<?endif;?>
</span><em>_(Drag-n-drop a PNG file or click the image at the left)_</em><input type="file" id="drop" accept="image/png" style="display:none">
:user_edit_custom_image_help:
<?if ($name=="root"):?>
&nbsp;
<?else:?>
_(Delete)_<input type="checkbox" name="confirmDelete" onChange="chkDelete(this.form, this.form.cmdUserEdit)">
<?endif;?>
: <input type="submit" name="cmdUserEdit" value="_(Apply)_" onclick="if (this.value=='_(Delete)_') this.value='Delete'; else this.value='Apply';" disabled><input type="button" value="_(Done)_" onclick="done('UserEdit')">
</form>
<br><br>
<form markdown="1" method="POST" action="/update.htm" onsubmit="return checkPassword(this)" target="progressFrame">
<input type="hidden" name="userName" value="<?=htmlspecialchars($name)?>">
_(Password)_:
<input type="hidden" name="userPassword" value="">
: <input type="password" name="userPasswordGUI" maxlength="129" autocomplete="new-password" onKeyUp="validatePassword(this.value);this.form.cmdUserEdit.disabled=(this.form.userPasswordGUI.value != this.form.userPasswordConfGUI.value);">
<i id="showPass" class="fa fa-eye" style="cursor:pointer" title="_(Show / Hide password)_" onclick="showPassword()"></i><span><span class="usage-disk sys none"><span id="strength-bar" style="width:0"></span><span></span></span><span id="strength-text"></span></span>
:user_password_help:
_(Retype password)_:
<input type="hidden" name="userPasswordConf" value="">
: <input type="password" name="userPasswordConfGUI" maxlength="129" autocomplete="new-password" onKeyUp="this.form.cmdUserEdit.disabled=(this.form.userPasswordGUI.value != this.form.userPasswordConfGUI.value);">
&nbsp;
: <input type="submit" name="cmdUserEdit" value="_(Change)_" onclick="this.value='Change'" disabled><input type="button" value="_(Done)_" onclick="done('UserEdit')">
</form>
<?if ($name == 'root'):?>
<form markdown="1" method="POST" action="/update.php" onsubmit="return checkKey(this)" target="progressFrame">
<input type="hidden" name="#include" value="/webGui/include/update.file.php">
<input type="hidden" name="#file" value="<?=$file;?>">
_(SSH authorized keys)_:
: <textarea spellcheck="false" cols="80" rows="<?=max(substr_count($text,"\n")+1,10)?>" maxlength="16384" name="text" style="resize:none;white-space:normal;font-family:bitstream;width:65.5%"><?=htmlspecialchars($text)?></textarea>
&nbsp;
: <input type="submit" value="_(Save)_" disabled><input type="button" value="_(Done)_" onclick="done()">
</form>
<?endif;?>
<?if ($name != 'root' && $var['shareSMBEnabled'] != 'no'):?>
<script>
var users = {};
var security = {};
var readList = {};
var writeList = {};
<?
$rw = 'read-write';
$ro = 'read-only';
$no = 'no-access';
foreach ($users as $user) {
$idx = $user['idx'];
if ($idx) echo "users[\"{$user['name']}\"]='$idx';\n";
}
foreach ($shares as $share => $data) {
echo "security[\"$share\"]=\"{$sec[$share]['security']}\";\n";
echo "readList[\"$share\"]=\"{$sec[$share]['readList']}\";\n";
echo "writeList[\"$share\"]=\"{$sec[$share]['writeList']}\";\n";
}
?>
function updateAccess(form,data,n,i) {
var name = "<?=$name?>";
if (data) {
if (n<i) {
$.post('/update.htm',data[n], function(){setTimeout(function(){updateAccess(form,data,++n,i);},3000);});
} else {
$('div.spinner.fixed').hide();
$('input[value="Reset"]').val('Done').prop('disabled',false).prop('onclick',null).off('click').click(function(){done('UserEdit');});
}
} else {
var data = [], i = 0;
$(form).find('select').each(function(){
if ($(this).prop('id')) {
var share = decodeURI($(this).prop('id'));
var read = readList[share].split(',');
var write = writeList[share].split(',');
var access = '';
data[i] = {};
data[i]['shareName'] = share;
data[i]['userAccess.0'] = '<?=$no?>';
for (var user in users) {
var idx = users[user];
switch (security[share]) {
case 'public':
access = '<?=$rw?>';
break;
case 'secure':
if (user == name) access = $(this).val();
else access = write.includes(user) ? '<?=$rw?>' : '<?=$ro?>';
break;
case 'private':
if (user == name) access = $(this).val();
else access = write.includes(user) ? '<?=$rw?>' : (read.includes(user) ? '<?=$ro?>' : '<?=$no?>');
break;
}
data[i]['userAccess.'+idx] = access;
}
data[i]['changeShareAccess'] = 'Apply';
i++;
}
});
$(form).find('input').prop('disabled',true);
$('div.spinner.fixed').show();
updateAccess(form,data,0,i);
}
}
</script>
<form markdown="1" method="POST">
<?
echo "<table class='share_status' style='margin-top:20px'>";
echo "<thead><tr><td>"._('Share')."</td><td>"._('Security')."</td><td>"._('User Access')."</td></tr></thead>";
echo "<tbody>";
foreach ($shares as $share => $data) {
if ($sec[$share]['export']=='-') continue;
$security = $sec[$share]['security'];
$read = in_array($name,explode(',',$sec[$share]['readList']));
$write = in_array($name,explode(',',$sec[$share]['writeList']));
switch ($security) {
case 'public' : $access = $rw; break;
case 'secure' : $access = $write ? $rw : $ro; break;
case 'private': $access = $write ? $rw : ($read ? $ro : $no); break;}
echo "<tr><td>$share</td><td>"._(ucfirst($security))."</td><td><select onchange='$(this).prop(\"id\",\"".rawurlencode($share)."\")'>";
echo mk_option($access,$rw,_('Read/Write'));
if ($security!='public') echo mk_option($access,$ro,_('Read-only'));
if ($security=='private') echo mk_option($access,$no,_('No Access'));
echo "</select></td></tr>";
}
echo "</tbody>";
echo "</table>";
?>
&nbsp;
: <input type="button" value="_(Apply)_" onclick="updateAccess(this.form)" disabled><input type="button" value="_(Done)_" onclick="done('UserEdit')">
</form>
<?endif;?>
+47
View File
@@ -0,0 +1,47 @@
Menu="Users"
Title="Users"
Tag="users"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$submenu = !empty($display['users']) && substr($display['users'],0,5)!='Tasks';
if ($submenu) $path = './Users';
ksort($users);
?>
<style>
a.info span{top:66px;left:42px}
<?if ($themes1):?>
div#title{margin-top:-30px!important}
<?endif;?>
</style>
<div id="title" class="title"><span class="left"><i class="fa fa-bell title"></i>_(Management Access)_</span></div>
<?$img = "/boot/config/plugins/dynamix/users/root.png"?>
<div class="user-list" style="text-align:center"><a class="<?=(!empty($users['root']['desc']) ? 'info' : '')?>" href="<?=$path?>/UserEdit?name=root"><img src="<?=(file_exists($img) ? autov($img) : '/webGui/images/user.png')?>" class="picture" border="0" width="48" height="48"><br>root<span><?=htmlspecialchars($users['root']['desc'])?></span></a></div>
<div class="title"><span class="left"><i class="fa fa-cloud title"></i>_(Shares Access)_</span></div>
<?foreach ($users as $user):?>
<?if ($user['name'] == 'root') continue;?>
<?$img = "/boot/config/plugins/dynamix/users/{$user['name']}.png"?>
<div class="user-list" style="text-align:center"><a class="<?=(!empty($user['desc']) ? 'info' : '')?>" href="<?=$path?>/UserEdit?name=<?=htmlspecialchars(urlencode($user['name']))?>"><img src="<?=(file_exists($img) ? autov($img) : '/webGui/images/user.png')?>" class="picture" border="0" width="48" height="48"><br><?=htmlspecialchars($user['name'])?><span><?=htmlspecialchars($user['desc'])?></span></a></div>
<?endforeach;?>
<?if (count($users)==1):?>
_(No users are defined)_. _(Click **Add User** to create a user for remote shares access)_
<?endif;?>
<div style='clear:both'></div>
<form method="POST" action="<?=$path?>/UserAdd">
<input type="submit" value="_(Add User)_"><?if ($submenu):?><input type="button" value="_(Done)_" onclick="done()"><?endif;?>
</form>
@@ -0,0 +1,4 @@
Menu="Settings:3"
Type="menu"
Title="User Preferences"
Tag="star"
+5
View File
@@ -0,0 +1,5 @@
Menu="$display['users'] Tasks:3"
Type="xmenu"
Title="Users"
Icon="icon-users"
Code="e945"
+4
View File
@@ -0,0 +1,4 @@
Menu="Settings"
Title="User Utilities"
Type="menu"
Tag="cogs"
+5
View File
@@ -0,0 +1,5 @@
Menu="NetworkServices"
Type="xmenu"
Title="VPN Manager"
Icon="icon-vpn"
Tabs="false"
+36
View File
@@ -0,0 +1,36 @@
Menu="WebGui"
Title="Vars"
Icon="icon-vars"
Tag="code"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?if (_var($display,'resize')):?>
<script>
function resize() {
$('pre.up').height(Math.max(window.innerHeight-320,330));
}
$(function() {
resize();
$(window).bind('resize',function(){resize();});
});
</script>
<?endif;?>
<?
$myPage['text'] = $page['text'] = $pages['Vars']['text'] = $language = $text = $notes = $site = '...';
$globals = $GLOBALS;
ksort($globals);
if (isset($globals['_SERVER']['PHP_AUTH_PW'])) $globals['_SERVER']['PHP_AUTH_PW'] = "***";
echo "<pre class='up'>",htmlspecialchars(print_r($globals,true)),"</pre>";
?>
<input type="button" value="_(Done)_" onclick="done()">
File diff suppressed because it is too large Load Diff
+466
View File
@@ -0,0 +1,466 @@
Menu="parentname:nnn"
Title="Tunnel wgX"
Tag="icon-vpn"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$check_wgX = in_array('wgX',$active) ? 'true' : 'false';
$start_wgX = in_array('wgX',$autostart);
$peer_wgX = $wgX = [];
$netpool['wgX'] = long2ip(ip2long($netpool['wg0'])+XXX*256);
$netpool6['wgX'] = str_replace(':0:0:',':XXX:0:',$netpool6['wg0']);
$netport['wgX'] = $netport['wg0']+XXX;
// read current configuration
[$conf_wgX,$cfg_wgX,$this_wgX,$vpn_wgX] = readConf($peer_wgX,$wgX,'wgX');
?>
<script>
netbase['wgX'] = <?=_var($netbase,'wgX')?>;
netpool['wgX'] = "<?=_var($netpool,'wgX')?>";
netport['wgX'] = "<?=_var($netport,'wgX')?>";
netbase6['wgX'] = "<?=_var($netbase6,'wgX')?>";
netpool6['wgX'] = "<?=_var($netpool6,'wgX')?>";
tstate['wgX'] = "<?=$check_wgX ? 'active' : 'passive'?>";
$(function(){
var ctrl = "<span class='status vhshift hshift'><i id='block-wgX' class='fa fa-fw fa-chevron-up' style='cursor:pointer' onclick='blockToggle(&quot;wgX&quot;)'></i></span>";
ctrl += "<span class='even wide'><span class='status vshift label'>_(Autostart)_</span><span class='status vhshift'><input type='checkbox' id='start-wgX' style='display:none'<?=$start_wgX?' checked':''?>></span></span>";
ctrl += "<span class='even'><span class='status vhshift'><input type='checkbox' id='view-wgX' style='display:none'></span></span>";
ctrl += "<span class='even'><span class='status vhshift'><input type='checkbox' id='toggle-wgX' style='display:none'></span></span>";
var form = $(document.wgX);
getPublicIP($('#endpoint-wgX').val(),'wgX',$('#protocol-wgX').val());
$('div.title').each(function(){if ($(this).html().indexOf('status vhshift')==-1) {$(this).find('span.left').append(ctrl);return false;}});
$('#start-wgX').switchButton({labels_placement:'left',off_label:"_(Off)_",on_label:"_(On)_"});
$('#start-wgX').change(function(){
var start = $('#start-wgX').is(':checked') ? 'on' : 'off';
$.post('/webGui/include/update.wireguard.php',{'#cmd':'autostart','#start':start,'#vtun':'wgX'});
});
$('#toggle-wgX').switchButton({labels_placement:'left',off_label:"_(Inactive)_",on_label:"_(Active)_",checked:<?=$check_wgX?>});
$('#toggle-wgX').change(function(e){
<?if ($this_wgX):?>
e.preventDefault();
e.stopPropagation();
var wg = $('#toggle-wgX').is(':checked') ? 'start' : 'stop';
var type = 0;
$('div[id^="index-wgX-"]').each(function(){
var temp = $(this).find('select[name^="TYPE:"]').val();
if (temp >= 7 && type==0) type = temp;
});
$.post('/webGui/include/update.wireguard.php',{'#cmd':'toggle','#wg':wg,'#vtun':'wgX','#type':type},function(ok){
if (wg=='start') {
if (ok==0) tstate['wgX']='active'; else $('#toggle-wgX').switchButton({checked:false});
} else {
if (ok==0) tstate['wgX']=''; else $('#toggle-wgX').switchButton({checked:true});
}
<?if (empty($wgX['UPNP:0'])):?>
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':'wgX','#link':'<?=$link?>','#ip':'<?=$server?>','#wg':tstate['wgX']},function(data){$('span.upnp.wgX').text(data);});
<?endif;?>
});
<?else:?>
$('#toggle-wgX').prop('checked',false).trigger('change');
<?endif;?>
});
if ($.cookie('view-wgX')=='advanced') {
$('.advanced.wgX').show();
form.find('i.fa-chevron-down').removeClass('fa-chevron-down').addClass('fa-chevron-up');
form.find('input[class*="zone"]').show();
form.find('i[class*="zone"]').each(function(i){if (!form.find('input[name="PublicKey:'+i+'"]').val()) {
$('div.wgX.key'+i).show();
$(this).removeClass('key-off').addClass('key-off');
}});
}
$('#view-wgX').switchButton({labels_placement:'left',off_label:"_(Basic)_",on_label:"_(Advanced)_",checked:$.cookie('view-wgX')=='advanced'});
$('#view-wgX').change(function(){
if ($.cookie('view-wgX')==null) {
// advanced view
$.cookie('view-wgX','advanced',{expires:3650});
$('.advanced.wgX').show('slow');
form.find('input[class*="zone"]').show('slow');
form.find('i.fa-chevron-down').removeClass('fa-chevron-down').addClass('fa-chevron-up');
form.find('i[class*="zone"]').each(function(i){if (!form.find('input[name="PublicKey:'+i+'"]').val()) {
$('div.wgX.key'+i).show('slow');
$(this).removeClass('key-off').addClass('key-off');
}});
} else {
// basic view
$.removeCookie('view-wgX');
$('.advanced.wgX').hide('slow');
form.find('i.fa-chevron-up').removeClass('fa-chevron-up').addClass('fa-chevron-down');
form.find('i[class*="zone"]').each(function(i){if (form.find('input[name="PublicKey:'+i+'"]').val()) {
form.find('input[class$="zone'+i+'"]').hide('slow');
$('div.wgX.key'+i).hide('slow');
$(this).removeClass('key-off');
}});
}
});
showRemark(form);
setProtocol(form,'wgX');
form.find('input[name^="Address:"]').each(function(){
var i = $(this).attr('name').split(':')[1];
if (i > 0) $(this).on('input change',function(){form.find('#ping-button1-'+i).prop('disabled',$(this).val()=='');});
});
form.find('input[name^="Address6:"]').each(function(){
var i = $(this).attr('name').split(':')[1];
if (i > 0) $(this).on('input change',function(){form.find('.ping-button6-'+i).prop('disabled',$(this).val()=='');});
});
form.find('input[name^="gui:Endpoint:"]').each(function(){
var i = $(this).attr('name').split(':')[2];
$(this).on('input change',function(){
form.find('#ping-button2-'+i).prop('disabled',$(this).val()=='');
});
});
if (!$.cookie('block-wgX')) $('div#block-wgX').show(); else $('i#block-wgX').removeClass('fa-chevron-up').addClass('fa-chevron-down');
if (xml) {
$('div.upnp.wgX').show();
<?if (empty($wgX['UPNP:0'])):?>
$.post('/webGui/include/update.wireguard.php',{'#cmd':'upnpc','#xml':xml,'#vtun':'wgX','#link':'<?=$link?>','#ip':'<?=$server?>','#wg':$.cookie('my-wgX')||''},function(data){$('span.upnp.wgX').text(data);});
<?endif;?>
} else {
form.find('select[name="UPNP:0"]').val('no');
}
var vpn = 0, lan = false
form.find('select[name^="TYPE:"]').each(function(){
var i = $(this).attr('name').split(':')[1];
if ($(this).val()>=7 && vpn==0) vpn = $(this).val();
lan |= $(this).val()=='6' || $(this).val() % 2;
form.find('input[name="DNS:'+i+'"]').attr('placeholder',$(this).val()>=7 ? "(_(not used)_)" : "(_(optional)_)");
showAccess(form,i,$(this).val());
});
if (vpn > 0) {
form.find('select[name="NAT:0"]').val('no').prop('disabled',true);
form.find('#addpeer-wgX').prop('disabled',true);
}
else if (form.find('select[name="NAT:0"]').val()=='no' && lan) $('span#my-static1-wgX').show();
else if (lan) $('span#my-static2-wgX').show();
});
</script>
<div markdown="1" id="block-wgX" style="display:none">
<form markdown="1" name="wgX" autocomplete="off" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareSettings($(this),'wgX')">
<input type="hidden" name="#include" value="/webGui/include/update.wireguard.php">
<input type="hidden" name="#file" value="<?=$conf_wgX?>">
<input type="hidden" name="#cfg" value="<?=$cfg_wgX?>">
<input type="hidden" name="#cmd" value="update">
<input type="hidden" name="#name" value="<?=$tower?>">
<input type="hidden" name="#vtun" value="wgX">
<input type="hidden" name="#type" value="0">
<input type="hidden" name="#wg" value="">
<input type="hidden" name="#internet" value="<?=$public?>">
<input type="hidden" name="#subnets1" value="">
<input type="hidden" name="#subnets2" value="">
<input type="hidden" name="#shared1" value="">
<input type="hidden" name="#shared2" value="">
<input type="hidden" name="#deleted" value="">
<input type="hidden" name="#locale" value="<?=$locale?>">
_(Local name)_:
: <span class="input"><input type="text" name="Name:0" class="wide" maxlength="99" value="<?=_var($wgX,"Name:0")?>" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)"></span>
<span class="pin"><i class="fa fa-fw fa-eye eye0<?=$this_wgX?'':' key-off'?>" style="cursor:pointer" onclick="WGconfig(this,'wgX','')" title="_(View Local Config)_"></i>
<i class="fa fa-fw fa-key zone0<?=isset($wgX['PublicKey:0'])?'':' key-off'?>" style="cursor:pointer" onclick="openClose($(document.wgX),null,'div.key0')" title="_(Toggle keys)_"></i>
<i id="chevron-wgX-0" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wgX),this,'div.zone0')" title="_(Toggle view)_"></i></span>
:wg_local_name_help:
<div markdown="1" class="keys wgX key0"<?=isset($wgX['PublicKey:0'])?' style="display:none">':'>'?>
_(Local private key)_:
: <span class="input"><input type="text" name="PrivateKey:0" class="wide private-0" maxlength="64" value="<?=_var($wgX,'PrivateKey:0')?>" onchange="highlight($(document.wgX),this,0)" placeholder="(_(mandatory)_)" required></span>
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wgX),'0')">
:wg_generate_keypair_help:
_(Local public key)_:
: <span class="input"><input type="text" name="PublicKey:0" class="wide public-0" maxlength="64" value="<?=_var($wgX,'PublicKey:0')?>" onchange="highlight($(document.wgX),this,0)" placeholder="(_(mandatory)_)" required></span>
:wg_generate_keypair_help:
</div>
<div markdown="1" class="advanced wgX zone0" style="display:none">
_(Network protocol)_:
: <span class="input"><select id="protocol-wgX" name="PROT:0" class="subnet" onchange="setProtocol($(document.wgX),'wgX',true)">
<?=mk_option(_var($wgX,'PROT:0'), "", _("IPv4 only"))?>
<?=mk_option(_var($wgX,'PROT:0'), "6", _("IPv6 only"))?>
<?=mk_option(_var($wgX,'PROT:0'), "46", _("IPv4 + IPv6"))?>
</select></span>
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Local tunnel network pool)_:
<input type="hidden" name="Network:0" value="">
: <span class="input"><input type="text" name="gui:Network:0" class="subnet" maxlength="15" value="<?=explode('/',_var($wgX,'Network:0'))[0]?>" onchange="setPool($(document.wgX),'wgX')" pattern="<?=$validIP4?>" title="_(IPv4 network)_" placeholder="<?=_var($netpool,'wgX')?>">/
<input type="number" name="gui:Mask:0" class="mask" min="1" max="32" value="<?=my_explode('/',_var($wgX,'Network:0'))[1]?>" onchange="if(quickValidate(this)) {setPool($(document.wgX),'wgX')}" placeholder="24"></span>
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Local tunnel network pool IPv6)_:
<input type="hidden" name="Network6:0" value="">
: <span class="input"><input type="text" name="gui:Network6:0" class="subnet" maxlength="40" value="<?=explode('/',_var($wgX,'Network6:0'))[0]?>" onchange="setPool6($(document.wgX),'wgX')" pattern="<?=$validIP6?>" title="_(IPv6 network)_" placeholder="<?=_var($netpool6,'wgX')?>">/
<input type="number" name="gui:Mask6:0" class="mask" min="1" max="128" value="<?=my_explode('/',_var($wgX,'Network6:0'))[1]?>" onchange="if(quickValidate(this)) {setPool6($(document.wgX),'wgX')}" placeholder="64"></span>
</div>
:wg_local_tunnel_network_pool_X_help:
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Local tunnel address)_:
: <span class="input"><input type="text" name="Address:0" class="subnet" maxlength="15" value="<?=_var($wgX,'Address:0')?:long2ip(_var($netbase,'wgX')+1)?>" onchange="verifyInSubnet(this);" pattern="<?=$validIP4?>" title="_(IPv4 address)_"></span>
:wg_local_tunnel_address_help:
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Local tunnel address IPv6)_:
: <span class="input"><input type="text" name="Address6:0" class="subnet" maxlength="40" value="<?=_var($wgX,'Address6:0')?:(_var($netbase6,'wgX').'1')?>" onchange="verifyInSubnet6(this);" pattern="<?=$validIP6?>" title="_(IPv6 address)_"></span>
:wg_local_tunnel_address_help:
</div>
</div>
_(Local endpoint)_:
: <span class="input"><input type="text" id="endpoint-wgX" name="Endpoint:0" class="subnet" value="<?=$vpn_wgX?'':_var($wgX,'Endpoint:0')?>" onchange="toLC(this);quickValidate(this);" pattern="<?=$validText?>" title="_(IP address or FQDN)_" placeholder="<?=$vpn_wgX?'(_(not used)_)':preg_replace('/^(www\.).+(\.unraid.net)$/','$1<hash>$2',$public)?>">:
<input type="number" name="gui:ListenPort:0" class="port" min="1" max="65535" value="<?=$vpn_wgX?'':_var($wgX,'ListenPort:0')?>" onchange="if(quickValidate(this)) {portRemark($(document.wgX),'wgX',this.value)}" placeholder="<?=$vpn_wgX?'':_var($netport,'wgX')?>"></span>
<span class="remark block" style="display:none">_(Remark)_: _(configure your router with port forwarding of port)_ **<span id="my-port-wgX"><?=_var($wgX,'ListenPort:0')?:_var($netport,'wgX')?></span>/_(UDP)_** _(to)_ **<?=$server?>:<?=_var($wgX,'ListenPort:0')?:_var($netport,'wgX')?>**</span><span class="upnp wgX block"></span>
<input type="hidden" name="ListenPort:0" value=""><dl id="endpoint4-wgX" style="display:none"></dl><dl id="endpoint6-wgX" style="display:none"></dl>
:wg_local_endpoint_X_help:
<div markdown="1" class="advanced wgX zone0" style="display:none">
_(Local server uses NAT)_:
: <span class="input"><select name="NAT:0" class="narrow" onchange="showRoute($(document.wgX),'wgX',0)">
<?=mk_option(_var($wgX,'NAT:0'), "", _("Yes"))?>
<?=mk_option(_var($wgX,'NAT:0'), "no", _("No"))?>
</select></span>
<span id="my-static1-wgX" class="block" style="display:none">_(Remark)_: _(configure your router with a static route of)_ **<?=_var($wgX,'Network:0')?>** _(to)_ **<?=$server?>**</span><span id="my-static2-wgX" class="block" style="display:none">_(Remark)_: _(docker containers on custom networks need static routing)_ **<?=_var($wgX,'Network:0')?>** _(to)_ **<?=$server?>**</span>
:wg_local_server_uses_nat_help:
<div markdown="1" class="upnp wg0" style="display:none">
_(Local gateway uses UPnP)_:
: <span class="input"><select name="UPNP:0" class="narrow" onchange="showRemark($(document.wgX))">
<?=mk_option(_var($wgX,'UPNP:0'), "", _("Yes"))?>
<?=mk_option(_var($wgX,'UPNP:0'), "no", _("No"))?>
</select></span>
:wg_local_gateway_uses_upnp_help:
</div>
_(Local tunnel firewall)_:
: <span class="input"><input type="text" name="DROP:0" class="wide" value="<?=_var($wgX,'DROP:0')?>" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(optional)_)"></span>
_(Rule)_: <select name="RULE:0" class="auto">
<?=mk_option(_var($wgX,'RULE:0'), "", _("Deny"))?>
<?=mk_option(_var($wgX,'RULE:0'), "1", _("Allow"))?>
</select>
:wg_local_tunnel_firewall_help:
_(MTU size)_:
: <span class="input"><input type="number" name="MTU:0" class="trim" min="68" max="9198" value="<?=_var($wgX,'MTU:0')?>" onchange="quickValidate(this);" placeholder="(_(automatic)_)">_(bytes)_</span>
:wg_mtu_size_help:
<!--
_(DNS servers)_:
: <span class="input"><input type="text" name="DNS:0" class="wide" value="" placeholder="(_(optional)_)"></span>
> Not used at the moment. It gives errors when used together with Unraid.
-->
</div>
<input type="hidden" name="PostUp:0:0" value="<?=$postUp0?>">
<input type="hidden" name="PostUp:0:1" value="<?=$postUp1?>">
<input type="hidden" name="PostUp:0:2" value="">
<input type="hidden" name="PostDown:0:0" value="<?=$postDown0?>">
<input type="hidden" name="PostDown:0:1" value="<?=$postDown1?>">
<input type="hidden" name="PostDown:0:2" value="">
:wg_peer_configuration_help:
<div id="peers-list-wgX" style="display:none"></div>
<?foreach ($peer_wgX as $i):?>
<div markdown="1" id="index-wgX-<?=$i?>" class="shade-<?=$display['theme']?>">
_(Peer name)_:
: <span class="input"><input type="text" name="Name:<?=$i?>" class="wide" maxlength="99" value="<?=_var($wgX,"Name:$i")?>" onchange="quickValidate(this);" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Delete Peer)_" onclick="delPeer($(document.wgX),'#index-wgX-<?=$i?>')">
<span class="pin"><i class="fa fa-fw fa-eye eye<?=$i?><?=(file_exists("$etc/peers/peer-$tower-wgX-$i.conf")&&isset($wgX["TYPE:$i"])&&$wgX["TYPE:$i"]<=6)?'':' key-off'?>" style="cursor:pointer" onclick="WGconfig(this,'peer-<?=$tower?>-wgX-<?=$i?>','/peers')" title="_(View Peer Config)_"></i>
<i class="fa fa-fw fa-key zone<?=$i?><?=isset($wgX["PublicKey:$i"])?'':' key-off'?>" style="cursor:pointer" onclick="openClose($(document.wgX),null,'div.key<?=$i?>')" title="_(Toggle keys)_"></i>
<i id="chevron-wgX-<?=$i?>" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wgX),this,'div.zone<?=$i?>')" title="_(Toggle view)_"></i></span>
:wg_peer_name_help:
_(Peer type of access)_:
: <span class="input"><select name="TYPE:<?=$i?>" class="auto" onchange="updatePeer($(document.wgX),<?=$i?>,this.value,'wgX')">
<?=mk_option(_var($wgX,"TYPE:$i"), "0", _("Remote access to server"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "1", _("Remote access to LAN"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "2", _("Server to server access"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "3", _("LAN to LAN access"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "4", _("Server hub & spoke access"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "5", _("LAN hub & spoke access"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "6", _("Remote tunneled access"))?>
<?=mk_option(_var($wgX,"TYPE:$i"), "7", _("VPN tunneled access for system"),count($peer_wgX)==1?'':'disabled')?>
<?=mk_option(_var($wgX,"TYPE:$i"), "8", _("VPN tunneled access for docker"))?>
</select></span>
<span id="access-type-<?=$i?>" class="access-type"></span>
<?if ($i==1):?>
> ![](<?=autov('/webGui/images/wireguard-help.png')?>)
<?endif;?>
<div markdown="1" class="keys wgX key<?=$i?>"<?=isset($wgX["PublicKey:$i"])?' style="display:none">':'>'?>
_(Peer private key)_:
: <span class="input"><input type="text" name="PrivateKey:<?=$i?>" class="wide private-<?=$i?>" maxlength="64" value="<?=_var($wgX,"PrivateKey:$i")?>" onchange="highlight($(document.wgX),this,<?=$i?>)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wgX),'<?=$i?>')">
:wg_generate_keypair_help:
_(Peer public key)_:
: <span class="input"><input type="text" name="PublicKey:<?=$i?>" class="wide public-<?=$i?>" maxlength="64" value="<?=_var($wgX,"PublicKey:$i")?>" onchange="highlight($(document.wgX),this,<?=$i?>)" placeholder="(_(mandatory)_)" required></span>
:wg_generate_keypair_help:
_(Peer preshared key)_:
: <span class="input"><input type="text" name="PresharedKey:<?=$i?>" class="wide preshared-<?=$i?>" maxlength="64" value="<?=_var($wgX,"PresharedKey:$i")?>" onchange="highlight($(document.wgX),this,<?=$i?>)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Key)_" onclick="presharedkey($(document.wgX),'<?=$i?>')">
:wg_peer_preshared_key_help:
</div>
<div markdown="1" class="advanced wgX zone<?=$i?>" style="display:none">
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Peer tunnel address)_:
: <span class="input"><input type="text" name="Address:<?=$i?>" class="subnet" maxlength="15" value="<?=_var($wgX,"Address:$i")?>" onchange="if(verifyInSubnet(this)){setAllow($(document.wgX),this.value,<?=$i?>)}" pattern="<?=$validIP4?>" title="_(IPv4 address)_"></span>
<input type="button" class="form ping-button1-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address:<?=$i?>&quot;]')"<?=isset($wgX["Address:$i"])?'':' disabled'?>>
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Peer tunnel address IPv6)_:
: <span class="input"><input type="text" name="Address6:<?=$i?>" class="subnet" maxlength="40" value="<?=_var($wgX,"Address6:$i")?>" onchange="if(verifyInSubnet6(this)){setAllow6($(document.wgX),this.value,<?=$i?>)}" pattern="<?=$validIP6?>" title="_(IPv6 address)_"></span>
<input type="button" class="form ping-button6-<?=$i?>" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address6:<?=$i?>&quot;]')"<?=isset($wgX["Address6:$i"])?'':' disabled'?>>
</div>
:wg_peer_tunnel_address_help:
_(Peer endpoint)_:
<input type="hidden" name="Endpoint:<?=$i?>" value="">
: <span class="input"><input type="text" name="gui:Endpoint:<?=$i?>" class="subnet" value="<?=_var($wgX,"Endpoint:$i")?>" pattern="<?=$validText?>" title="_(IP address or FQDN)_" onchange="toLC(this);quickValidate(this);" <?=($vpn_wgX||(int)_var($wgX,"TYPE:$i",0)==2||(int)_var($wgX,"TYPE:$i",0)==3)?'placeholder="(_(mandatory)_)" required':'placeholder="(_(not used)_)"'?>>:
<input type="number" name="gui:ListenPort:<?=$i?>" class="port" min="1" max="65535" value="<?=_var($wgX,"ListenPort:$i")?>" onchange="quickValidate(this);"<?=isset($wgX["Endpoint:$i"])?" placeholder=\"".(_var($wgX,'ListenPort:0')?:_var($netport,'wgX'))."\"":""?>></span>
<input type="button" class="form ping-button2-<?=$i?>" value="Ping" onclick="ping($(document.wgX),this,'input[name=&quot;gui:Endpoint:<?=$i?>&quot;]')"<?=isset($wgX["Endpoint:$i"])?'':' disabled'?>>
:wg_peer_endpoint_help:
_(Peer allowed IPs)_:
: <span class="input"><input type="text" name="AllowedIPs:<?=$i?>" class="wide" value="<?=_var($wgX,"AllowedIPs:$i")?>" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(mandatory)_)" required></span>
:wg_peer_allowed_ips_help:
_(Peer DNS server)_:
: <span class="input"><input type="text" name="DNS:<?=$i?>" class="subnet" maxlength="40" value="<?=_var($wgX,"DNS:$i")?>" onchange="quickValidate(this);" pattern="<?=$validDNSServerList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_"<?=(int)_var($wgX,"TYPE:$i",0)!=6?'placeholder="(_(optional)_)"':'placeholder="(_(mandatory)_)" required'?>></span>
:wg_peer_dns_server_help:
_(Persistent keepalive)_:
: <span class="input"><input type="number" name="PersistentKeepalive:<?=$i?>" class="trim" min="0" max="600" value="<?=_var($wgX,"PersistentKeepalive:$i")?>" onchange="quickValidate(this);" placeholder="(_(disabled)_)">_(seconds)_</span>
:wg_persistent_keepalive_help:
</div>
<span class="pin">_(Data received)_: <span class="rx-wgX-<?=$i?>">0 B</span>_(Data sent)_: <span class="tx-wgX-<?=$i?>">0 B</span><br>_(Last handshake)_: <span class="hs-wgX-<?=$i?>">_(unknown)_</span></span>
</div>
<?endforeach;?>
&nbsp;
: <input type="submit" value="_(Apply)_" onclick="return(validateForm($(document.wgX),'wgX'))" disabled><input type="button" value="_(Done)_" onclick="done()"><input type="button" id="addpeer-wgX" value="_(Add Peer)_" onclick="addPeer($(document.wgX),'wgX')"><input type="button" class="advanced wgX" value="_(Delete Tunnel)_" style="float:right;display:none" onclick="delTunnel('wgX')">
</form>
<script markdown="1" type="text/html" id="peer-template-wgX">
<div markdown="1" id="index-wgX-INDEX" class="shade-<?=$display['theme']?>">
_(Peer name)_:
: <span class="input"><input type="text" name="Name:INDEX" class="wide" maxlength="99" value="" onchange="quickValidate(this);" pattern="<?=$validname?>" title="_(Use only letters A-Z, digits or space,dash,underscore)_" placeholder="(_(optional)_)"></span>
<span class="pin"><i class="fa fa-fw fa-eye eyeINDEX key-off" title="_(Show Peer Config)_"></i>
<i class="fa fa-fw fa-key zoneINDEX key-off" title="_(Toggle keys)_"></i>
<i id="chevron-wgX-INDEX" class="fa fa-fw fa-chevron-down" style="cursor:pointer" onclick="openClose($(document.wgX),this,'div.zoneINDEX')" title="_(Toggle view)_"></i></span>
:wg_peer_name_help:
_(Peer type of access)_:
: <span class="input"><select name="TYPE:INDEX" class="auto" onchange="updatePeer($(document.wgX),INDEX,this.value,'wgX')">
<?=mk_option(0, "0", _("Remote access to server"))?>
<?=mk_option(0, "1", _("Remote access to LAN"))?>
<?=mk_option(0, "2", _("Server to server access"))?>
<?=mk_option(0, "3", _("LAN to LAN access"))?>
<?=mk_option(0, "4", _("Server hub & spoke access"))?>
<?=mk_option(0, "5", _("LAN hub & spoke access"))?>
<?=mk_option(0, "6", _("Remote tunneled access"))?>
<?=mk_option(0, "7", _("VPN tunneled access for system"),'disabled')?>
<?=mk_option(0, "8", _("VPN tunneled access for docker"))?>
</select></span>
<span id="access-type-INDEX" class="access-type"></span>
> ![](<?=autov('/webGui/images/wireguard-help.png')?>)
<div markdown="1" class="keys wgX keyINDEX">
_(Peer private key)_:
: <span class="input"><input type="text" name="PrivateKey:INDEX" class="wide private-INDEX" maxlength="64" value="" onchange="highlight($(document.wgX),this,0)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Keypair)_" onclick="keypair($(document.wgX),'INDEX')">
:wg_generate_keypair_help:
_(Peer public key)_:
: <span class="input"><input type="text" name="PublicKey:INDEX" class="wide public-INDEX" maxlength="64" onchange="highlight($(document.wgX),this,0)" placeholder="(_(mandatory)_)" value="" required></span>
:wg_generate_keypair_help:
_(Peer preshared key)_:
: <span class="input"><input type="text" name="PresharedKey:INDEX" class="wide preshared-INDEX" maxlength="64" value="" onchange="highlight($(document.wgX),this,0)" placeholder="(_(optional)_)"></span>
<input type="button" class="form" value="_(Generate Key)_" onclick="presharedkey($(document.wgX),'INDEX')">
:wg_peer_preshared_key_help:
</div>
<div markdown="1" class="advanced wgX zoneINDEX" style="display:none">
<div markdown="1" class="ipv4 wgX" style="display:none">
_(Peer tunnel address)_:
: <span class="input"><input type="text" name="Address:INDEX" class="subnet" maxlength="15" value="" onchange="if(verifyInSubnet(this)){setAllow($(document.wgX),this.value,INDEX)}" pattern="<?=$validIP4?>" title="_(IPv4 address)_"></span>
<input type="button" class="form ping-button1-INDEX" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address:INDEX&quot;]')" disabled>
</div>
<div markdown="1" class="ipv6 wgX" style="display:none">
_(Peer tunnel address IPv6)_:
: <span class="input"><input type="text" name="Address6:INDEX" class="subnet" maxlength="40" value="" onchange="if(verifyInSubnet6(this)){setAllow6($(document.wgX),this.value,INDEX)}" pattern="<?=$validIP6?>" title="_(IPv6 address)_"></span>
<input type="button" class="form ping-button6-INDEX" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;Address6:INDEX&quot;]')" disabled>
</div>
:wg_peer_tunnel_address_help:
_(Peer endpoint)_:
<input type="hidden" name="Endpoint:INDEX" value="">
: <span class="input"><input type="text" name="gui:Endpoint:INDEX" class="subnet" value="" pattern="<?=$validText?>" title="_(IP address or FQDN)_" onchange="toLC(this);quickValidate(this);" placeholder="(_(not used)_)">:
<input type="number" name="gui:ListenPort:INDEX" class="port" min="1" max="65535" value="" onchange="quickValidate(this);"></span>
<input type="button" class="form ping-button2-INDEX" value="_(Ping)_" onclick="ping($(document.wgX),this,'input[name=&quot;gui:Endpoint:INDEX&quot;]')" disabled>
:wg_peer_endpoint_help:
_(Peer allowed IPs)_:
: <span class="input"><input type="text" name="AllowedIPs:INDEX" class="wide" value="" onchange="quickValidate(this);" pattern="<?=$validList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_, _(CIDR optional)_" placeholder="(_(mandatory)_)" required></span>
:wg_peer_allowed_ips_help:
_(Peer DNS server)_:
: <span class="input"><input type="text" name="DNS:INDEX" class="subnet" maxlength="40" value="" onchange="quickValidate(this);" pattern="<?=$validDNSServerList?>" title="_(Comma separated list of IPv4 and IPv6 IP addresses)_" placeholder="(_(optional)_)"></span>
:wg_peer_dns_server_help:
_(Persistent keepalive)_:
: <span class="input"><input type="number" name="PersistentKeepalive:INDEX" class="trim" min="0" max="600" value="" onchange="quickValidate(this);" placeholder="(_(disabled)_)">_(seconds)_</span>
:wg_persistent_keepalive_help:
</div>
</div>
</script>
</div>
+4
View File
@@ -0,0 +1,4 @@
Menu="Tools:20"
Type="menu"
Title="webGUI"
Tag="tv"

Some files were not shown because too many files have changed in this diff Show More