🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 97c049ed0a
commit 0acff03804
14253 files changed
+3893239

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

@@ -0,0 +1,637 @@
'use strict';
'require dom';
'require form';
'require fs';
'require ui';
'require uci';
'require view';
/*
Copyright 2022-2025 Rafał Wabik - IceG - From eko.one.pl forum
Licensed to the GNU General Public License v3.0.
*/
document.head.append(E('style', {'type': 'text/css'},
`
#smsTable {
width: 100%;
border: 1px solid var(--border-color-medium) !important;
}
th, td {
padding: 10px;
text-align: justify !important;
vertical-align: top !important;
}
td input[type="checkbox"] {
float: left !important;
margin: 0 auto !important;
width: 17px !important;
}
#smsTable tr:nth-child(odd) td{
background: var(--background-color-medium) !important;
border-bottom: 1px solid var(--border-color-medium) !important;
border-top: 1px solid var(--border-color-medium) !important;
}
#smsTable tr:nth-child(even) td{
border-bottom: 1px solid var(--border-color-medium) !important;
border-top: 1px solid var(--border-color-medium) !important;
}
#smsTable .checker {
width: 7% !important;
}
#smsTable .from {
width: 11% !important;
}
#smsTable .received {
width: 15% !important;
}
#smsTable .message {
width: 88% !important;
}
`));
function msg_bar(v, m) {
var pg = document.querySelector('#msg')
var vn = parseInt(v) || 0;
var mn = parseInt(m) || 100;
var pc = Math.floor((100 / mn) * vn);
pg.firstElementChild.style.width = pc + '%';
pg.setAttribute('title', '%s'.format(v) + ' / ' + '%s'.format(m) + ' ('+ pc + '%)');
}
function save_count() {
uci.load('sms_tool_js').then(function() {
var storeL = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'storage'));
var portR = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'readport'));
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , 'status' ]))
.then(function(res) {
if (res) {
var total = res.substring(res.indexOf("total"));
var t = total.replace ( /[^\d.]/g, '' );
var used = res.substring(17, res.indexOf("total"));
var u = used.replace ( /[^\d.]/g, '' );
uci.set('sms_tool_js', '@sms_tool_js[0]', 'sms_count', L.toArray(u).join(' '));
uci.save();
uci.apply();
}
});
});
}
return view.extend({
load: function() {
uci.load('sms_tool_js');
},
handleSWarea: function(ev) {
switch (document.querySelector('input[name="filter_area"]:checked').value) {
case 'sim':
uci.set('sms_tool_js', '@sms_tool_js[0]', 'storage', "SM");
uci.save();
uci.apply();
break;
case 'memory':
uci.set('sms_tool_js', '@sms_tool_js[0]', 'storage', "ME");
uci.save();
uci.apply();
break;
}
},
handleDelete: function(ev) {
if (document.querySelectorAll('input[name="smsn"]:checked').length == 0){
ui.addNotification(null, E('p', _('Please select the message(s) to be deleted')), 'info');
}
else {
if (document.querySelectorAll('input[name="smsn"]:checked').length === document.querySelectorAll('input[name="smsn"]').length) {
if (confirm(_('Delete all the messages?')))
{
var sections = uci.sections('sms_tool_js');
var portDA = sections[0].readport;
var storeDA = sections[0].storage;
fs.exec_direct('/usr/bin/sms_tool', [ '-d' , portDA , 'delete' , 'all' ]);
document.getElementById("ch-all").checked = false;
var rowCount = smsTable.rows.length;
for (var i = rowCount - 1; i > 0; i--) {
smsTable.deleteRow(i);}
setTimeout(function() {
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeDA , '-d' , portDA , 'status' ]))
.then(function(res) {
if (res) {
var total = res.substring(res.indexOf("total"));
var t = total.replace ( /[^\d.]/g, '' );
var u = "0";
msg_bar(Math.floor(u), t);
save_count();
}
});
}, 2000);
}
}
else {
if (confirm(_('Delete selected message(s)?')))
{
uci.load('sms_tool_js').then(function() {
var storeL = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'storage'));
var portR = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'readport'));
var array = [];
var checkb = document.querySelectorAll('input[type=checkbox]:checked');
for (var i = 0; i < checkb.length; i++) {
if (checkb[i] != source)
array.push(checkb[i].id)
}
if (array) {
var args = [];
var sections = uci.sections('sms_tool_js');
var portDEL = sections[0].readport;
var storeDS = sections[0].storage;
args.push(array);
var ax = args.toString();
ax = ax.replace(/,/g, ' ');
ax = ax.replace(/-/g, ' ');
var smsnr = ax.split(" ");
var smsallchars = smsnr.toString();
var smsdelcount = 0;
var smsdeleted = 0;
var inumber = false;
for (var i = 0; i < smsallchars.length; i++) {
var ch = smsallchars[i];
if (ch >= '0' && ch <= '9') {
if (!inumber) {
smsdelcount++;
inumber = true;
}
} else if (ch === ',') {
inumber = false;
} else {
inumber = false;
}
}
var deletelabel = document.getElementById("deleteinfo");
deletelabel.style.display = 'block';
for (var i=0; i < smsnr.length + 2; i++)
{
(function(i) {
setTimeout(function() {
smsnr[i] = parseInt(smsnr[i], 10);
if (!Number.isNaN(smsnr[i]))
{
fs.exec_direct('/usr/bin/sms_tool', [ '-d' , portDEL , 'delete' , smsnr[i] ]);
smsdeleted++;
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , 'status' ]))
.then(function(res) {
if (res) {
var total = res.substring(res.indexOf("total"));
var t = total.replace ( /[^\d.]/g, '' );
var used = res.substring(17, res.indexOf("total"));
var u = used.replace ( /[^\d.]/g, '' );
msg_bar(Math.floor(u), t);
deletelabel.innerHTML = _('Please wait... deleted')+' '+smsdeleted+' '+_('of')+' '+smsdelcount+' '+_('selected messages');
}
});
}
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , 'status' ]))
.then(function(res) {
if (res) {
var total = res.substring(res.indexOf("total"));
var t = total.replace ( /[^\d.]/g, '' );
var used = res.substring(17, res.indexOf("total"));
var u = used.replace ( /[^\d.]/g, '' );
msg_bar(Math.floor(u), t);
deletelabel.innerHTML = _('Please wait... deleted')+' '+smsdeleted+' '+_('of')+' '+smsdelcount+' '+_('selected messages');
}
});
if (smsdelcount == smsdeleted) {
setTimeout(function() {
var hidecount = document.getElementById('deleteinfo');
hidecount.style.display = 'none';
save_count();
}, 7000);
}
}, 1500 * i);
})(i);
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , 'status' ]))
.then(function(res) {
if (res) {
var total = res.substring(res.indexOf("total"));
var t = total.replace ( /[^\d.]/g, '' );
var used = res.substring(17, res.indexOf("total"));
var u = used.replace ( /[^\d.]/g, '' );
msg_bar(Math.floor(u), t);
deletelabel.innerHTML = _('Please wait... deleted')+' '+smsdeleted+' '+_('of')+' '+smsdelcount+' '+_('selected messages');
}
});
}
var table = document.getElementById("smsTable");
var index = 1;
while (index < table.rows.length) {
var input = table.rows[index].cells[0].children[0];
if (input && input.checked) {
table.deleteRow(index);
}
else {
index++;
}
}
}
});
}
}
}
},
handleRefresh: function(ev) {
window.location.reload();
},
handleSelect: function(ev) {
var checkBox = document.getElementById("ch-all");
var checkBoxes = document.querySelectorAll('input[type="checkbox"]');
if (checkBox.checked == true){
for (var i = 0; i < checkBoxes.length; i++)
checkBoxes[i].setAttribute('checked', 'true');
} else {
for (var i = 0; i < checkBoxes.length; i++)
checkBoxes[i].removeAttribute('checked');
}
},
render: function(data) {
var sections, store;
var view = document.getElementById("smssarea");
store = '-';
uci.load('sms_tool_js').then(function() {
var storeL = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'storage'));
var portR = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'readport'));
var smsM = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'mergesms'));
var algo = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'algorithm'));
var hide = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'bnumber'));
var ledn = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'lednotify'));
var ledt = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'ledtype'));
var direct = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'direction'));
if (!portR) {
ui.addNotification(null, E('p', _('The package requires user configuration. \
<br /><br /><b>The following need to be set:</b> \
<ul><li>1. All ports for communication with the modem.</li><li>2. Additional options specific to the given modem (for handling USSD codes).</li><li> \
3. Notification LED (optional).</li><li><ul>')), 'info');
}
var sections = uci.sections('sms_tool_js');
var led = sections[0].smsled;
if (storeL == "SM")
document.querySelector('input[name="filter_area"][value="sim"]').checked = true;
if (storeL == "ME")
document.querySelector('input[name="filter_area"][value="memory"]').checked = true;
if (ledn == "1")
{
switch (ledt) {
case 'S':
fs.exec_direct('/etc/init.d/led', [ 'restart' ]);
break;
case 'D':
fs.write('/sys/class/leds/'+led+'/brightness', '0');
break;
default:
}
}
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , 'status' ]))
.then(function(res) {
if (res) {
var total = res.substring(res.indexOf("total"));
var t = total.replace ( /[^\d.]/g, '' );
var used = res.substring(17, res.indexOf("total"));
var u = used.replace ( /[^\d.]/g, '' );
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , '-f' , '%Y-%m-%d %H:%M' , '-j' , 'recv' , '2>/dev/null' ]))
.then(function(res2) {
if (res2) {
var table = document.getElementById('smsTable');
while (table.rows.length > 1) { table.deleteRow(1); }
var start = res2.substring(7);
var end = start.substring(0,start.length-2);
var json = JSON.parse(end);
var aidx = [];
/* Merging messages */
if (smsM == "1") {
var result = [];
if (algo == "Advanced")
{
switch (direct) {
case 'Start':
var Data = json.sort((a, b) => {
if (a.timestamp === b.timestamp && a.sender === b.sender) {
return a.part - b.part;
} else if (a.timestamp === b.timestamp) {
return a.sender - b.sender;
} else {
return a.timestamp.localeCompare(b.timestamp);
}
});
break;
case 'End':
var Data = json.sort((a, b) => {
if (a.timestamp === b.timestamp && a.sender === b.sender) {
return b.part - a.part;
} else if (a.timestamp === b.timestamp) {
return a.sender - b.sender;
} else {
return a.timestamp.localeCompare(b.timestamp);
}
});
break;
default:
}
var SortedSMS = Data.sort((function (a, b) { return new Date(b.timestamp) - new Date(a.timestamp) }));
var combinedjson = {};
for (const parts of SortedSMS) {
const { sender, timestamp, total, content, index } = parts;
if (total) {
const key = `${sender}-${timestamp}-${total}`;
if (combinedjson[key]) {
combinedjson[key].content += content;
combinedjson[key].index += '-' + index;
} else {
combinedjson[key] = { sender, timestamp, total, content, index };
}
} else {
const newkey = `${sender}-${timestamp}-${index}`;
combinedjson[newkey] = { sender, timestamp, total, content, index };
}
}
var result = Object.values(combinedjson); }
if (algo == "Simple")
{
var SortedSMS = json.sort((function (a, b) { return new Date(b.timestamp) - new Date(a.timestamp) }));
SortedSMS.forEach(function (o) {
if (!this[o.sender]) {
this[o.sender] = { index: o.index, sender: o.sender, timestamp: o.timestamp, part: o.part, total: o.total, content: o.content };
result.push(this[o.sender]);
return;
}
if (this[o.sender].total == o.total && this[o.sender].timestamp == o.timestamp && this[o.sender].sender == o.sender && this[o.sender].part > 0) {
this[o.sender].index += '-' + o.index;
this[o.sender].content += o.content;}
else {
this[o.sender] = { index: o.index, sender: o.sender, timestamp: o.timestamp, part: o.part, total: o.total, content: o.content };
result.push(this[o.sender]);
return;
}
}, Object.create(null));
}
if (u){
var Lres = L.resource('icons/newdelsms.png');
var iconz = String.format('<img style="width: 24px; height: 24px; "src="%s"/>', Lres);
for (var i = 0; i < result.length; i++) {
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(0);
var cell3 = row.insertCell(0);
var cell4 = row.insertCell(0);
cell4.innerHTML = "<input type='checkbox' name='smsn' id="+result[i].index+","+" />"+iconz;
if (result[i].sender.includes(hide)) {
var removeLast5 = result[i].sender.slice(0, -5);
cell3.innerHTML = removeLast5 + '#####';
} else {
cell3.innerHTML = result[i].sender;
}
cell2.innerHTML = result[i].timestamp;
cell1.innerHTML = result[i].content.replace(/\s+/g, ' ').trim();
aidx.push(result[i].index+'-');
}
var axx = aidx.toString();
axx = axx.replace(/,/g, ' ');
axx = axx.replace(/-/g, ' ');
uci.set('sms_tool_js', '@sms_tool_js[0]', 'sms_count_index', L.toArray(axx).join(' '));
uci.set('sms_tool_js', '@sms_tool_js[0]', 'sms_count', L.toArray(u).join(' '));
uci.save();
uci.apply();
}
}
}
/* No merging messages */
if (smsM == "0") {
/* Sorting messages by delivery time */
var sortbyTime = json.sort((function (a, b) { return new Date(b.timestamp) - new Date(a.timestamp) }));
/* Sorting messages by parts */
var sortedData = sortbyTime.sort((a, b) => {
if (a.timestamp === b.timestamp && a.sender === b.sender && a.total === b.total) {
return a.part - b.part;
} else {
return 0;
}
});
if (u){
var Lres = L.resource('icons/newdelsms.png');
var iconz = String.format('<img style="width: 24px; height: 24px; "src="%s"/>', Lres);
for (var i = 0; i < sortedData.length; i++) {
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(0);
var cell3 = row.insertCell(0);
var cell4 = row.insertCell(0);
cell4.innerHTML = "<input type='checkbox' name='smsn' id="+sortedData[i].index+","+" />"+iconz;
if (sortedData[i].sender.includes(hide)) {
var removeLast5 = sortedData[i].sender.slice(0, -5);
cell3.innerHTML = removeLast5 + '#####';
} else {
cell3.innerHTML = sortedData[i].sender;
}
cell2.innerHTML = sortedData[i].timestamp;
cell1.innerHTML = sortedData[i].content.replace(/\s+/g, ' ').trim();
aidx.push(sortedData[i].index+'-');
}
var axx = aidx.toString();
axx = axx.replace(/,/g, ' ');
axx = axx.replace(/-/g, ' ');
uci.set('sms_tool_js', '@sms_tool_js[0]', 'sms_count_index', L.toArray(axx).join(' '));
uci.set('sms_tool_js', '@sms_tool_js[0]', 'sms_count', L.toArray(u).join(' '));
uci.save();
uci.apply();
}
}
});
} else {
if ( t.lenght < 1 )
{
msg_bar(Math.floor(u), t);
}
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
}
if (document.getElementById('msg')) {
msg_bar(Math.floor(u), t);
}
});
});
var v = E([], [
E('h2', _('SMS Messages')),
E('div', { 'class': 'cbi-map-descr' }, _('User interface for reading messages using sms-tool. More information about the sms-tool on the %seko.one.pl forum%s.').format('<a href="https://eko.one.pl/?p=openwrt-sms_tool" target="_blank">', '</a>')),
E('h3', _('Received Messages')),
E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ _('Message storage area') ]),
E('td', { 'class': 'td' }, [
E('div', [
E('label', {
'data-tooltip': _('Any change in the area from which SMS messages will be read requires refreshing the messages')
}, [
E('input', {
'type': 'radio',
'name': 'filter_area',
'value': 'sim',
'change': ui.createHandlerFn(this, 'handleSWarea'),
'checked': true
}),
' ',
_('SIM card')
]),
' \u00a0 ',
E('label', {
'data-tooltip': _('Any change in the area from which SMS messages will be read requires refreshing the messages')
}, [
E('input', {
'type': 'radio',
'name': 'filter_area',
'value': 'memory',
'change': ui.createHandlerFn(this, 'handleSWarea')
}),
' ',
_('Modem memory')
])
])
])
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'width': '33%' }, [ _('Storage used / Total capacity') ]),
E('td', { 'class': 'td' }, [
E('div', { 'class': 'right' }, [
E('div', {
'id': 'msg',
'class': 'cbi-progressbar',
'title': '-'
}, E('div')),
E('div', { 'class': 'right' }, [
E('div', {
'style': 'text-align:center;font-size:90%',
'id': 'deleteinfo'
}, [ '' ]),
]),
]),
]),
]),
]),
E('div', { 'class': 'right' }, [
E('button', {
//'class': 'cbi-button cbi-button-negative important',
'class': 'cbi-button cbi-button-remove',
'id': 'execute',
'click': ui.createHandlerFn(this, 'handleDelete')
}, [ _('Delete message(s)') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-add',
'id': 'clr',
'click': ui.createHandlerFn(this, 'handleRefresh')
}, [ _('Refresh messages') ]),
]),
E('p'),
E('table', { 'class': 'table' , 'id' : 'smsTable' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th checker' },
E('input', {
'id': 'ch-all',
'type': 'checkbox',
'name': 'checkall',
'disabled': null,
'checked': null,
'click': ui.createHandlerFn(this, 'handleSelect')
}), '',
),
E('th', { 'class': 'th from' }, _('From')),
E('th', { 'class': 'th received' }, _('Received')),
E('th', { 'class': 'th center message' }, _('Message'))
])
]),
]);
return v;
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});
@@ -0,0 +1,187 @@
'use strict';
'require dom';
'require form';
'require fs';
'require ui';
'require uci';
'require view';
/*
Copyright 2022-2025 Rafał Wabik - IceG - From eko.one.pl forum
Licensed to the GNU General Public License v3.0.
*/
return view.extend({
handleCommand: function(exec, args) {
let buttons = document.querySelectorAll('.cbi-button');
for (let i = 0; i < buttons.length; i++)
buttons[i].setAttribute('disabled', 'true');
return fs.exec(exec, args).then(function(res) {
let out = document.querySelector('.atcommand-output');
out.style.display = '';
res.stdout = res.stdout?.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") || '';
res.stderr = res.stderr?.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") || '';
if (res.stdout === undefined || res.stderr === undefined || res.stderr.includes('undefined') || res.stdout.includes('undefined')) {
return;
}
else {
dom.content(out, [ res.stdout || '', res.stderr || '' ]);
}
}).catch(function(err) {
if (res.stdout === undefined || res.stderr === undefined || res.stderr.includes('undefined') || res.stdout.includes('undefined')) {
return;
}
else {
ui.addNotification(null, E('p', [ err ]));
}
}).finally(function() {
for (let i = 0; i < buttons.length; i++)
buttons[i].removeAttribute('disabled');
});
},
handleGo: function(ev) {
let atcmd = document.getElementById('cmdvalue').value;
let sections = uci.sections('sms_tool_js');
let port = sections[0].atport;
if ( atcmd.length < 2 )
{
ui.addNotification(null, E('p', _('Please specify the command to send')), 'info');
return false;
}
else {
if ( !port )
{
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
return false;
}
else {
//sms_tool -d /dev/ttyUSB1 at "ati"
return this.handleCommand('sms_tool', [ '-d' , port , 'at' , atcmd ]);
}
}
if ( !port )
{
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
return false;
}
},
handleClear: function(ev) {
let out = document.querySelector('.atcommand-output');
out.style.display = 'none';
let ov = document.getElementById('cmdvalue');
ov.value = '';
document.getElementById('cmdvalue').focus();
},
handleCopy: function(ev) {
let out = document.querySelector('.atcommand-output');
out.style.display = 'none';
let ov = document.getElementById('cmdvalue');
ov.value = '';
let x = document.getElementById('tk').value;
ov.value = x;
},
load: function() {
return Promise.all([
L.resolveDefault(fs.read_direct('/etc/modem/atcmmds.user'), null),
uci.load('sms_tool_js')
]);
},
render: function (loadResults) {
let info = _('User interface for sending AT commands using sms-tool. More information about the sms-tool on the %seko.one.pl forum%s.').format('<a href="https://eko.one.pl/?p=openwrt-sms_tool" target="_blank">', '</a>');
return E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('h2', {}, [ _('AT Commands') ]),
E('div', { 'class': 'cbi-map-descr'}, info),
E('hr'),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-node' }, [
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('User AT commands') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('select', { 'class': 'cbi-input-select',
'id': 'tk',
'style': 'margin:5px 0; width:100%;',
'change': ui.createHandlerFn(this, 'handleCopy'),
'mousedown': ui.createHandlerFn(this, 'handleCopy')
},
(loadResults[0] || "").trim().split("\n").map(function(cmd) {
let fields = cmd.split(/;/);
let name = fields[0];
let code = fields[1] || fields[0];
return E('option', { 'value': code }, name );
})
)
])
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('Command to send') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('input', {
'style': 'margin:5px 0; width:100%;',
'type': 'text',
'id': 'cmdvalue',
'data-tooltip': _('Press [Enter] to send the command, press [Delete] to delete the command'),
'keydown': function(ev) {
if (ev.keyCode === 13)
{
let execBtn = document.getElementById('execute');
if (execBtn) {
execBtn.click();
}
}
if (ev.keyCode === 46)
{
let del = document.getElementById('cmdvalue');
if (del) {
let ov = document.getElementById('cmdvalue');
ov.value = '';
document.getElementById('cmdvalue').focus();
}
}
}
}),
])
]),
])
]),
E('hr'),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'cbi-button cbi-button-remove',
'id': 'clr',
'click': ui.createHandlerFn(this, 'handleClear')
}, [ _('Clear form') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-action important',
'id': 'execute',
'click': ui.createHandlerFn(this, 'handleGo')
}, [ _('Send command') ]),
]),
E('p', _('Reply')),
E('pre', { 'class': 'atcommand-output', 'style': 'display:none; border: 1px solid var(--border-color-medium); border-radius: 5px; font-family: monospace' }),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
})
@@ -0,0 +1,329 @@
'use strict';
'require dom';
'require form';
'require fs';
'require ui';
'require uci';
'require view';
/*
Copyright 2022-2025 Rafał Wabik - IceG - From eko.one.pl forum
Licensed to the GNU General Public License v3.0.
*/
return view.extend({
handleCommand: function(exec, args) {
let buttons = document.querySelectorAll('.cbi-button');
for (let i = 0; i < buttons.length; i++)
buttons[i].setAttribute('disabled', 'true');
return fs.exec(exec, args).then(function(res) {
let out = document.querySelector('.smscommand-output');
out.style.display = '';
res.stdout = res.stdout?.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") || '';
res.stderr = res.stderr?.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") || '';
let cut = res.stdout;
cut = cut.substr(0, 20);
if ( cut == "sms sent sucessfully" ) {
res.stdout = _('SMS sent sucessfully');
}
dom.content(out, [ res.stdout || '', res.stderr || '' ]);
}).catch(function(err) {
ui.addNotification(null, E('p', [ err ]))
}).finally(function() {
for (let i = 0; i < buttons.length; i++)
buttons[i].removeAttribute('disabled');
});
},
handleGo: function(ev) {
let phn = document.getElementById('phonenumber').value;
let sections = uci.sections('sms_tool_js');
let port = sections[0].sendport;
let dx = sections[0].delay * 1000;
let get_smstxt = document.getElementById('smstext').value;
let elem = document.getElementById('execute');
let vN = elem.innerText;
if (vN.includes(_('Send to number')) == true)
{
if ( phn.length < 3 )
{
ui.addNotification(null, E('p', _('Please enter phone number')), 'info');
return false;
}
else {
if ( !port )
{
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
return false;
}
else {
if ( get_smstxt.length < 1 )
{
ui.addNotification(null, E('p', _('Please enter a message text')), 'info');
return false;
}
else {
// sms_tool -d /dev/ttyUSB1 send 48500500500 "MSG"
return this.handleCommand('sms_tool', [ '-d' , port , 'send' , phn , get_smstxt ]);
}
}
}
if ( !port )
{
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
return false;
}
}
else {
if ( !port )
{
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
return false;
}
else {
if ( get_smstxt.length < 1 )
{
ui.addNotification(null, E('p', _('Please enter a message text')), 'info');
return false;
}
else {
// sms_tool -d /dev/ttyUSB1 send 48500500500 "MSG"
let xs = document.getElementById('pb');
let phone, i;
res.stdout = '';
for (let i = 0; i < xs.length; i++) {
(function(i) {
setTimeout(function() {
phone = xs.options[i].value;
let out = document.querySelector('.smscommand-output');
out.style.display = '';
fs.exec_direct('/usr/bin/sms_tool', [ '-d' , port , 'send' , phone , get_smstxt ]);
res.stdout += (i+1)+_('/')+xs.length+' * '+_('[Bot] Message sent to number:') + ' ' + phone +'\n';
res.stdout = res.stdout.replace(/undefined/g, "");
dom.content(out, [ res.stdout || '' ]);
}, dx * i);
})(i);
}
}
}
}
},
handleClear: function(ev) {
let out = document.querySelector('.smscommand-output');
out.style.display = '';
out.style.display = 'none';
let ovc = document.getElementById('phonenumber');
let ov2 = document.getElementById('smstext');
ov2.value = '';
document.getElementById('counter').innerHTML = '160';
let prefixnum, sections = uci.sections('sms_tool_js');
let addprefix = sections[0].prefix;
if ( addprefix == '1' )
{
prefixnum = sections[0].pnumber;
ovc.value = prefixnum;
}
else {
ovc.value = '';
}
document.getElementById('phonenumber').focus();
},
handleCopy: function(ev) {
let out = document.querySelector('.smscommand-output');
out.style.display = 'none';
let ov = document.getElementById('phonenumber');
ov.value = '';
let x = document.getElementById('pb').value;
ov.value = x;
},
load: function() {
return Promise.all([
L.resolveDefault(fs.read_direct('/etc/modem/phonebook.user'), null),
uci.load('sms_tool_js')
]);
},
render: function (loadResults) {
let group, prefixnum, sections = uci.sections('sms_tool_js');
if ( sections[0].sendingroup == '1' )
{
group = 1;
}
else {
group = '';
}
if ( sections[0].prefix == '1' ) {
prefixnum = sections[0].pnumber;
}
if ( sections[0].information == '1' ) {
ui.addNotification(null, E('p', _('The phone number should be preceded by the country prefix (for Poland it is 48, without +). If the number is 5, 4 or 3 characters, it is treated as.. short and should not be preceded by a country prefix.') ), 'info');
}
let info = _('User interface for sending messages using sms-tool. More information about the sms-tool on the %seko.one.pl forum%s.').format('<a href="https://eko.one.pl/?p=openwrt-sms_tool" target="_blank">', '</a>');
return E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('h2', {}, [ _('SMS Messages') ]),
E('div', { 'class': 'cbi-map-descr'}, info),
E('hr'),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-node' }, [
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('User contacts') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('select', { 'class': 'cbi-input-select',
'id': 'pb',
'style': 'margin:5px 0; width:100%;',
'change': ui.createHandlerFn(this, 'handleCopy'),
'mousedown': ui.createHandlerFn(this, 'handleCopy')
},
(loadResults[0] || "").trim().split("\n").map(function(cmd) {
let fields = cmd.split(/;/);
let name = fields[0];
let code = fields[1] || fields[0];
return E('option', { 'value': code }, name );
})
)
])
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('Send to') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('input', {
'style': 'margin:5px 0; width:100%;',
'type': 'text',
'id': 'phonenumber',
'value': prefixnum,
'oninput': "this.value = this.value.replace(/[^0-9.]/g, '');",
'data-tooltip': _('Press [Delete] to delete the phone number'),
'keydown': function(ev) {
if (ev.keyCode === 46)
{
let del = document.getElementById('phonenumber');
if (del) {
let ovc = document.getElementById('phonenumber');
let prefixnum, sections = uci.sections('sms_tool_js');
let addprefix = sections[0].prefix;
if ( addprefix == '1' )
{
prefixnum = sections[0].pnumber;
ovc.value = prefixnum;
}
else {
ovc.value = '';
}
document.getElementById('phonenumber').focus();
}
}
},
}),
])
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('Message text') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('textarea', {
'id': 'smstext',
'style': 'width: 100%; resize: vertical; height:80px; max-height:80px; min-height:80px; min-width:100%;',
'wrap': 'on',
'rows': '3',
'placeholder': _(''),
'maxlength': '160',
'data-tooltip': _('Press [Delete] to delete the content of the message'),
'keydown': function(ev) {
if (ev.keyCode === 46)
{
let del = document.getElementById('smstext');
if (del) {
let ovtxt = document.getElementById('smstext');
ovtxt.value = '';
document.getElementById('smstext').focus();
}
}
},
'keyup': function(ev) {
document.getElementById('counter').innerHTML = (160 - document.getElementById('smstext').value.length);
this.value = this.value.replace(/ą/g, 'a').replace(/Ą/g, 'A');
this.value = this.value.replace(/ć/g, 'c').replace(/Ć/g, 'C');
this.value = this.value.replace(/ę/g, 'e').replace(/Ę/g, 'E');
this.value = this.value.replace(/ł/g, 'l').replace(/Ł/g, 'L');
this.value = this.value.replace(/ń/g, 'n').replace(/Ń/g, 'N');
this.value = this.value.replace(/ó/g, 'o').replace(/Ó/g, 'O');
this.value = this.value.replace(/ś/g, 's').replace(/Ś/g, 'S');
this.value = this.value.replace(/ż/g, 'z').replace(/Ż/g, 'Z');
this.value = this.value.replace(/ź/g, 'z').replace(/Ź/g, 'Z');
}
}),
E('div', { 'class': 'left' }, [
E('br'),
E('label', { 'id': 'counter' }, [ _('160') ])
])
]),
]),
])
]),
E('hr'),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'cbi-button cbi-button-remove',
'id': 'clr',
'click': ui.createHandlerFn(this, 'handleClear')
}, [ _('Clear form') ]),
'\xa0\xa0\xa0',
E('span', { 'class': 'diag-action' }, [
group ? new ui.ComboButton('send', {
'send': '%s %s'.format(_('Send'), _('to number')),
'sendg': '%s %s'.format(_('Send'), _('to group')),
}, {
'click': ui.createHandlerFn(this, 'handleGo'),
'id': 'execute',
'classes': {
'send': 'cbi-button cbi-button-action important',
'sendg': 'cbi-button cbi-button-action important',
},
'id': 'execute',
}).render() : E('button', {
'class': 'cbi-button cbi-button-action important',
'id': 'execute',
'click': ui.createHandlerFn(this, 'handleGo')
}, [ _('Send to number') ]),
]),
]),
E('p', _('Status')),
E('pre', { 'class': 'smscommand-output', 'id': 'ans', 'style': 'display:none; border: 1px solid var(--border-color-medium); border-radius: 5px; font-family: monospace' }),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
})
@@ -0,0 +1,385 @@
'use strict';
'require dom';
'require form';
'require fs';
'require ui';
'require uci';
'require view';
/*
Copyright 2022-2025 Rafał Wabik - IceG - From eko.one.pl forum
Licensed to the GNU General Public License v3.0.
*/
return view.extend({
handleCommand: function(exec, args) {
let buttons = document.querySelectorAll('.cbi-button');
for (let i = 0; i < buttons.length; i++)
buttons[i].setAttribute('disabled', 'true');
return fs.exec(exec, args).then(function(res) {
let out = document.querySelector('.ussdcommand-output');
let fullhistory = document.getElementById('history-full')?.checked;
let reversereplies = document.getElementById('reverse-replies')?.checked;
out.style.display = '';
res.stdout = res.stdout?.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") || '';
res.stderr = res.stderr?.replace(/^(?=\n)$|^\s*|\s*$|\n\n+/gm, "") || '';
if (res.stdout === undefined || res.stderr === undefined || res.stderr.includes('undefined') || res.stdout.includes('undefined')) {
return;
} else {
let cut = res.stderr;
if ( cut.length > 2 ) {
if (cut.includes('error: 0'))
res.stdout = _('Phone/Modem failure.');
if (cut.includes('error: 1'))
res.stdout = _('No connection to phone.');
if (cut.includes('error: 2'))
res.stdout = _('Phone/Modem adapter link reserved.');
if (cut.includes('error: 3'))
res.stdout = _('Operation not allowed.');
if (cut.includes('error: 4'))
res.stdout = _('Operation not supported.');
if (cut.includes('error: 5'))
res.stdout = _('PH_SIM PIN required.');
if (cut.includes('error: 6'))
res.stdout = _('PH_FSIM PIN required.');
if (cut.includes('error: 7'))
res.stdout = _('PH_FSIM PUK required.');
if (cut.includes('error: 10'))
res.stdout = _('SIM not inserted.');
if (cut.includes('error: 11'))
res.stdout = _('SIM PIN required.');
if (cut.includes('error: 12'))
res.stdout = _('SIM PUK required.');
if (cut.includes('error: 13'))
res.stdout = _('SIM failure.');
if (cut.includes('error: 14'))
res.stdout = _('SIM busy.');
if (cut.includes('error: 15'))
res.stdout = _('SIM wrong.');
if (cut.includes('error: 16'))
res.stdout = _('Incorrect password.');
if (cut.includes('error: 17'))
res.stdout = _('SIM PIN2 required.');
if (cut.includes('error: 18'))
res.stdout = _('SIM PUK2 required.');
if (cut.includes('error: 20'))
res.stdout = _('Memory full.');
if (cut.includes('error: 21'))
res.stdout = _('Invalid index.');
if (cut.includes('error: 22'))
res.stdout = _('Not found.');
if (cut.includes('error: 23'))
res.stdout = _('Memory failure.');
if (cut.includes('error: 24'))
res.stdout = _('Text string too long.');
if (cut.includes('error: 25'))
res.stdout = _('Invalid characters in text string.');
if (cut.includes('error: 26'))
res.stdout = _('Dial string too long.');
if (cut.includes('error: 27'))
res.stdout = _('Invalid characters in dial string.');
if (cut.includes('error: 30'))
res.stdout = _('No network service.');
if (cut.includes('error: 31'))
res.stdout = _('Network timeout.');
if (cut.includes('error: 32'))
res.stdout = _('Network not allowed, emergency calls only.');
if (cut.includes('error: 40'))
res.stdout = _('Network personalization PIN required.');
if (cut.includes('error: 41'))
res.stdout = _('Network personalization PUK required.');
if (cut.includes('error: 42'))
res.stdout = _('Network subset personalization PIN required.');
if (cut.includes('error: 43'))
res.stdout = _('Network subset personalization PUK required.');
if (cut.includes('error: 44'))
res.stdout = _('Service provider personalization PIN required.');
if (cut.includes('error: 45'))
res.stdout = _('Service provider personalization PUK required.');
if (cut.includes('error: 46'))
res.stdout = _('Corporate personalization PIN required.');
if (cut.includes('error: 47'))
res.stdout = _('Corporate personalization PUK required.');
if (cut.includes('error: 48'))
res.stdout = _('PH-SIM PUK required.');
if (cut.includes('error: 100'))
res.stdout = _('Unknown error.');
if (cut.includes('error: 103'))
res.stdout = _('Illegal MS.');
if (cut.includes('error: 106'))
res.stdout = _('Illegal ME.');
if (cut.includes('error: 107'))
res.stdout = _('GPRS services not allowed.');
if (cut.includes('error: 111'))
res.stdout = _('PLMN not allowed.');
if (cut.includes('error: 112'))
res.stdout = _('Location area not allowed.');
if (cut.includes('error: 113'))
res.stdout = _('Roaming not allowed in this location area.');
if (cut.includes('error: 126'))
res.stdout = _('Operation temporary not allowed.');
if (cut.includes('error: 132'))
res.stdout = _('Service operation not supported.');
if (cut.includes('error: 133'))
res.stdout = _('Requested service option not subscribed.');
if (cut.includes('error: 134'))
res.stdout = _('Service option temporary out of order.');
if (cut.includes('error: 148'))
res.stdout = _('Unspecified GPRS error.');
if (cut.includes('error: 149'))
res.stdout = _('PDP authentication failure.');
if (cut.includes('error: 150'))
res.stdout = _('Invalid mobile class.');
if (cut.includes('error: 256'))
res.stdout = _('Operation temporarily not allowed.');
if (cut.includes('error: 257'))
res.stdout = _('Call barred.');
if (cut.includes('error: 258'))
res.stdout = _('Phone/Modem is busy.');
if (cut.includes('error: 259'))
res.stdout = _('User abort.');
if (cut.includes('error: 260'))
res.stdout = _('Invalid dial string.');
if (cut.includes('error: 261'))
res.stdout = _('SS not executed.');
if (cut.includes('error: 262'))
res.stdout = _('SIM Blocked.');
if (cut.includes('error: 263'))
res.stdout = _('Invalid block.');
if (cut.includes('error: 527'))
res.stdout = _('Please wait, and retry your selection later (Specific Modem Sierra).');
if (cut.includes('error: 528'))
res.stdout = _('Location update failure – emergency calls only (Specific Modem Sierra).');
if (cut.includes('error: 529'))
res.stdout = _('Selection failure – emergency calls only (Specific Modem Sierra).');
if (cut.includes('error: 772'))
res.stdout = _('SIM powered down.');
dom.content(out, [ res.stderr || '', res.stdout ? ' > ' + res.stdout : '' ]);
} else {
if ( fullhistory ) {
const ussdreply = (res.stdout + res.stderr).replace(/^\s*\n+/g, '');
let ussdv = document.getElementById('cmdvalue');
ussdv.value = '';
document.getElementById('cmdvalue').focus();
if (reversereplies) {
out.innerText = ussdreply + (out.innerText.trim() ? '\n\n' + out.innerText : '');
} else {
out.innerText += '\n\n' + res.stdout + res.stderr;
out.innerText = out.innerText.replace(/^\s*\n+/g, '');
}
} else {
dom.content(out, [ res.stdout || '', res.stderr || '' ]);
}
}
}
}).catch(function(err) {
if (res.stdout === undefined || res.stderr === undefined || res.stderr.includes('undefined') || res.stdout.includes('undefined')) {
return;
} else {
ui.addNotification(null, E('p', [ err ]));
}
}).finally(function() {
for (let i = 0; i < buttons.length; i++)
buttons[i].removeAttribute('disabled');
});
},
handleGo: function(ev) {
let ussd = document.getElementById('cmdvalue').value;
let sections = uci.sections('sms_tool_js');
let port = sections[0].ussdport;
let get_ussd = sections[0].ussd;
let get_pdu = sections[0].pdu;
let get_coding = sections[0].coding;
let tool_args = [];
if ( ussd.length < 1 ) {
ui.addNotification(null, E('p', _('Please specify the code to send')), 'info');
return false;
}
if ( !port ) {
ui.addNotification(null, E('p', _('Please set the port for communication with the modem')), 'info');
return false;
}
tool_args.push('-d', port);
if (get_ussd == '1')
tool_args.push('-R');
if (get_pdu == '1')
tool_args.push('-r');
if (get_coding && get_coding != 'auto')
tool_args.push('-c', get_coding);
tool_args.push('ussd', ussd);
return this.handleCommand('sms_tool', tool_args);
},
handleClear: function(ev) {
let out = document.querySelector('.ussdcommand-output');
out.style.display = '';
out.style.display = 'none';
let fullhistory = document.getElementById('history-full')?.checked;
if ( fullhistory ) {
dom.content(out, [ '' ]);
}
let ov = document.getElementById('cmdvalue');
ov.value = '';
document.getElementById('cmdvalue').focus();
},
handleClearOut: function(ev) {
let out = document.querySelector('.ussdcommand-output');
let fullhistory = document.getElementById('history-full')?.checked;
if ( fullhistory ) {
out.style.display = '';
out.style.display = 'none';
dom.content(out, [ '' ]);
document.getElementById("reverse-replies").disabled = false;
document.getElementById("reverse-replies").checked = true;
} else {
document.getElementById("reverse-replies").disabled = true;
document.getElementById("reverse-replies").checked = false;
}
},
handleCopy: function(ev) {
let out = document.querySelector('.ussdcommand-output');
let fullhistory = document.getElementById('history-full')?.checked;
if ( !fullhistory ) {
out.style.display = 'none';
}
let ov = document.getElementById('cmdvalue');
ov.value = '';
let x = document.getElementById('tk').value;
ov.value = x;
},
load: function() {
return Promise.all([
L.resolveDefault(fs.read_direct('/etc/modem/ussdcodes.user'), null),
uci.load('sms_tool_js')
]);
},
render: function (loadResults) {
let info = _('User interface for sending USSD codes using sms-tool. More information about the sms-tool on the %seko.one.pl forum%s.').format('<a href="https://eko.one.pl/?p=openwrt-sms_tool" target="_blank">', '</a>');
return E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('h2', {}, [ _('USSD Codes') ]),
E('div', { 'class': 'cbi-map-descr'}, info),
E('hr'),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'cbi-section-node' }, [
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('User USSD codes') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('select', { 'class': 'cbi-input-select',
'id': 'tk',
'style': 'margin:5px 0; width:100%;',
'change': ui.createHandlerFn(this, 'handleCopy'),
'mousedown': ui.createHandlerFn(this, 'handleCopy')
},
(loadResults[0] || "").trim().split("\n").map(function(cmd) {
let fields = cmd.split(/;/);
let name = fields[0];
let code = fields[1] || fields[0];
return E('option', { 'value': code }, name );
})
)
])
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title' }, [ _('Code to send') ]),
E('div', { 'class': 'cbi-value-field' }, [
E('input', {
'style': 'margin:5px 0; width:100%;',
'type': 'text',
'id': 'cmdvalue',
'data-tooltip': _('Press [Enter] to send the code, press [Delete] to delete the code'),
'keydown': function(ev) {
if (ev.keyCode === 13) {
let execBtn = document.getElementById('execute');
if (execBtn) {
execBtn.click();
}
}
if (ev.keyCode === 46) {
let del = document.getElementById('cmdvalue');
if (del) {
let ov = document.getElementById('cmdvalue');
ov.value = '';
document.getElementById('cmdvalue').focus();
}
}
}
}),
])
]),
])
]),
E('div', { 'class': 'right' }, [
E('label', { 'class': 'cbi-checkbox' }, [
E('input', {
'id': 'history-full',
'click': ui.createHandlerFn(this, 'handleClearOut'),
'data-tooltip': _('Check this option if you need to use the menu built on USSD codes'),
'type': 'checkbox',
'name': 'showhistory',
'disabled': null
}), ' ',
E('label', { 'for': 'history-full' }), ' ',
_('Keep the previous reply when sending a new USSD code.')
]),
'\xa0\xa0\xa0',
E('label', { 'class': 'cbi-checkbox' }, [
E('input', {
'id': 'reverse-replies',
'data-tooltip': _('View new reply from top'),
'type': 'checkbox',
'name': 'reversereplies',
'disabled': true
}), ' ',
E('label', { 'for': 'reverse-replies' }), ' ',
_('Turn over the replies.')
])
]),
E('hr'),
E('div', { 'class': 'right' }, [
E('button', {
'class': 'cbi-button cbi-button-remove',
'id': 'clr',
'click': ui.createHandlerFn(this, 'handleClear')
}, [ _('Clear form') ]),
'\xa0\xa0\xa0',
E('button', {
'class': 'cbi-button cbi-button-action important',
'id': 'execute',
'click': ui.createHandlerFn(this, 'handleGo')
}, [ _('Send code') ]),
]),
E('p', _('Reply')),
E('pre', { 'class': 'ussdcommand-output', 'style': 'display:none; border: 1px solid var(--border-color-medium); border-radius: 5px; font-family: monospace' }),
]);
},
handleSaveApply: null,
handleSave: null,
handleReset: null
})
@@ -0,0 +1,369 @@
'use strict';
'require form';
'require fs';
'require view';
'require uci';
'require ui';
'require tools.widgets as widgets'
/*
Copyright 2022-2025 Rafał Wabik - IceG - From eko.one.pl forum
Licensed to the GNU General Public License v3.0.
*/
return view.extend({
load: function() {
return fs.list('/dev').then(function(devs) {
return devs.filter(function(dev) {
return dev.name.match(/^ttyUSB/) || dev.name.match(/^cdc-wdm/) || dev.name.match(/^ttyACM/) || dev.name.match(/^mhi_/) || dev.name.match(/^wwan/);
});
});
},
render: function(devs) {
let m, s, o;
m = new form.Map('sms_tool_js', _('Configuration sms-tool'), _('Configuration panel for sms-tool and gui application.'));
s = m.section(form.TypedSection, 'sms_tool_js', '', null);
s.anonymous = true;
//TAB SMS
s.tab('smstab' , _('SMS Settings'));
s.anonymous = true;
o = s.taboption('smstab' , form.Value, 'readport', _('SMS reading port'),
_('Select one of the available ttyUSBX ports.'));
devs.sort((a, b) => a.name > b.name);
devs.forEach(dev => o.value('/dev/' + dev.name));
o.placeholder = _('Please select a port');
o.rmempty = false;
o = s.taboption('smstab', form.ListValue, 'storage', _('Message storage area'),
_('Messages are stored in a specific location (for example, on the SIM card or modem memory), but other areas may also be available depending on the type of device.'));
o.value('SM', _('SIM card'));
o.value('ME', _('Modem memory'));
o.default = 'SM';
o = s.taboption('smstab', form.Flag, 'mergesms', _('Merge split messages'),
_('Checking this option will make it easier to read the messages, but it will cause a discrepancy in the number of messages shown and received.')
);
o.rmempty = false;
o = s.taboption('smstab' , form.ListValue, 'algorithm', _('Merge algorithm'),
_(''));
o.value('Simple', _('Simple (merge without sorting)'));
o.value('Advanced', _('Advanced (merges with sorting)'));
o.default = 'Advanced';
o.depends('mergesms', '1');
o = s.taboption('smstab' , form.ListValue, 'direction', _('Direction of message merging'),
_(''));
o.value('Start', _('From beginning to end'));
o.value('End', _('From end to beginning'));
o.default = 'Start';
o.depends('algorithm', 'Advanced');
o = s.taboption('smstab', form.Value, 'bnumber', _('Phone number to be blurred'),
_('The last 5 digits of this number will be blurred.')
);
o.password = true;
o = s.taboption('smstab', form.Button, '_fsave');
o.title = _('Save messages to a text file');
o.description = _('This option allows to backup SMS messages or, for example, save messages that are not supported by the sms-tool.');
o.inputtitle = _('Save as .txt file');
o.onclick = function() {
return uci.load('sms_tool_js').then(function() {
let portES = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'readport'));
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-d' , portES , '-f' , '%Y-%m-%d %H:%M' , 'recv' , '2>/dev/null']))
.then(function(res) {
if (res) {
fs.write('/tmp/mysms.txt', res.trim().replace(/\r\n/g, '\n') + '\n');
let fileName = 'mysms.txt';
let filePath = '/tmp/' + fileName;
fs.stat(filePath)
.then(function () {
if (confirm(_('Save sms to txt file?'))) {
L.resolveDefault(fs.read_direct('/tmp/mysms.txt'), null).then(function (restxt) {
if (restxt) {
L.ui.showModal(_('Saving...'), [
E('p', { 'class': 'spinning' }, _('Please wait.. Process of saving SMS message to a text file is in progress.'))
]);
let link = E('a', {
'download': 'mysms.txt',
'href': URL.createObjectURL(
new Blob([ restxt ], { type: 'text/plain' })),
});
window.setTimeout(function() {
link.click();
URL.revokeObjectURL(link.href);
L.hideModal();
}, 2000).finally();
} else {
ui.addNotification(null, E('p', {}, _('Saving SMS messages to a file failed. Please try again.')));
}
}).catch(() => {
ui.addNotification(null, E('p', {}, _('Download error') + ': ' + err.message));
});
}
});
}
});
});
};
o = s.taboption('smstab', form.Button, '_fdelete');
o.title = _('Delete all messages');
o.description = _("This option allows you to delete all SMS messages when they are not visible in the 'Received Messages' tab.");
o.inputtitle = _('Delete all');
o.onclick = function() {
if (confirm(_('Delete all the messages?'))) {
return uci.load('sms_tool_js').then(function() {
let portFD = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'readport'));
fs.exec_direct('/usr/bin/sms_tool', [ '-d' , portFD , 'delete' , 'all' ]);
});
}
};
o = s.taboption('smstab', form.Value, 'sendport', _('SMS sending port'),
_("Select one of the available ttyUSBX ports."));
devs.sort((a, b) => a.name > b.name);
devs.forEach(dev => o.value('/dev/' + dev.name));
o.placeholder = _('Please select a port');
o.rmempty = false;
o = s.taboption('smstab', form.Value, 'pnumber', _('Prefix number'),
_("The phone number should be preceded by the country prefix (for Poland it is 48, without '+'). If the number is 5, 4 or 3 characters, it is treated as 'short' and should not be preceded by a country prefix."));
o.default = '48';
o.validate = function(section_id, value) {
if (value.match(/^[0-9]+(?:\.[0-9]+)?$/))
return true;
return _('Expect a decimal value');
};
o = s.taboption('smstab', form.Flag, 'prefix', _('Add prefix to phone number'),
_('Automatically add prefix to the phone number field.')
);
o.rmempty = false;
//o.default = true;
o = s.taboption('smstab', form.Flag, 'sendingroup', _('Enable group messaging'),
_("This option allows you to send one message to all contacts in the user's contact list."));
o.rmempty = false;
o.default = false;
o = s.taboption('smstab', form.Value, 'delay', _('Message sending delay'),
_("[3 - 59] second(s) \
<br /><br /><b>Important</b> \
<br />Messages are sent without verification and confirmation delivery of the message. \
Therefore, there is a risk of non-delivery of the message."));
o.default = "3";
o.rmempty = false;
o.validate = function(section_id, value) {
if (value.match(/^[0-9]+(?:\.[0-9]+)?$/) && +value >= 3 && +value < 60)
return true;
return _('Expect a decimal value between three and fifty-nine');
};
o.depends("sendingroup", "1");
o.datatype = 'range(3, 59)';
o = s.taboption('smstab', form.Flag, 'information', _('Explanation of number and prefix'),
_('In the tab for sending SMSes, show an explanation of the prefix and the correct phone number.')
);
o.rmempty = false;
//o.default = true;
o = s.taboption('smstab', form.TextValue, '_tmp2', _('User contacts'),
_("Each line must have the following format: 'Contact name;phone number'. For user convenience, the file is saved to the location <code>/etc/modem/phonebook.user</code>."));
o.rows = 7;
o.cfgvalue = function(section_id) {
return fs.trimmed('/etc/modem/phonebook.user');
};
o.write = function(section_id, formvalue) {
return fs.write('/etc/modem/phonebook.user', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
};
//TAB USSD
s.tab('ussd', _('USSD Codes Settings'));
s.anonymous = true;
o = s.taboption('ussd', form.Value, 'ussdport', _('USSD sending port'),
_('Select one of the available ttyUSBX ports.'));
devs.sort((a, b) => a.name > b.name);
devs.forEach(dev => o.value('/dev/' + dev.name));
o.placeholder = _('Please select a port');
o.rmempty = false;
o = s.taboption('ussd', form.Flag, 'ussd', _('Sending USSD code in plain text'),
_('Send the USSD code in plain text. Command is not being coded to the PDU.')
);
o.rmempty = false;
o = s.taboption('ussd', form.Flag, 'pdu', _('Receive message without PDU decoding'),
_('Receive and display the message without decoding it as a PDU.')
);
o.rmempty = false;
o = s.taboption('ussd', form.ListValue, 'coding', _('PDU decoding scheme'));
o.value('auto', _('Autodetect'));
o.value('0', _('7Bit'));
o.value('2', _('UCS2'));
o.default = 'auto';
o = s.taboption('ussd', form.TextValue, '_tmp4', _('User USSD codes'),
_("Each line must have the following format: 'Code description;code'. For user convenience, the file is saved to the location <code>/etc/modem/ussdcodes.user</code>."));
o.rows = 7;
o.cfgvalue = function(section_id) {
return fs.trimmed('/etc/modem/ussdcodes.user');
};
o.write = function(section_id, formvalue) {
return fs.write('/etc/modem/ussdcodes.user', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
};
//TAB AT
s.tab('attab', _('AT Commands Settings'));
s.anonymous = true;
o = s.taboption('attab' , form.Value, 'atport', _('AT commands sending port'),
_('Select one of the available ttyUSBX ports.'));
devs.sort((a, b) => a.name > b.name);
devs.forEach(dev => o.value('/dev/' + dev.name));
o.placeholder = _('Please select a port');
o.rmempty = false;
o = s.taboption('attab' , form.TextValue, '_tmp6', _('User AT commands'),
_("Each line must have the following format: 'At command description;AT command'. For user convenience, the file is saved to the location <code>/etc/modem/atcmmds.user</code>."));
o.rows = 20;
o.cfgvalue = function(section_id) {
return fs.trimmed('/etc/modem/atcmmds.user');
};
o.write = function(section_id, formvalue) {
return fs.write('/etc/modem/atcmmds.user', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
};
//TAB INFO
s.tab('notifytab', _('Notification Settings'));
s.anonymous = true;
o = s.taboption('notifytab', form.Flag, 'lednotify', _('Notify new messages'),
_('The LED informs about a new message. Before activating this function, please config and save the SMS reading port, time to check SMS inbox and select the notification LED.')
);
o.rmempty = false;
o.default = true;
o.write = function(section_id, value) {
uci.load('sms_tool_js').then(function() {
let storeL = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'storage'));
let portR = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'readport'));
let dsled = (uci.get('sms_tool_js', '@sms_tool_js[0]', 'ledtype'));
L.resolveDefault(fs.exec_direct('/usr/bin/sms_tool', [ '-s' , storeL , '-d' , portR , 'status' ]))
.then(function(res) {
if (res) {
let total = res.substring(res.indexOf('total'));
let t = total.replace ( /[^\d.]/g, '' );
let used = res.substring(17, res.indexOf('total'));
let u = used.replace ( /[^\d.]/g, '' );
let sections = uci.sections('sms_tool_js');
let led = sections[0].smsled;
if (value == '1') {
uci.set('sms_tool_js', '@sms_tool_js[0]', 'sms_count', L.toArray(u).join(' '));
uci.set('sms_tool_js', '@sms_tool_js[0]', 'lednotify', "1");
uci.save();
fs.exec_direct('/sbin/new_cron_sync.sh');
fs.exec_direct('/etc/init.d/my_new_sms', [ 'enable' ]);
fs.exec('sleep 2');
fs.exec_direct('/etc/init.d/my_new_sms', [ 'start' ]);
}
if (value == '0') {
uci.set('sms_tool_js', '@sms_tool_js[0]', 'lednotify', "0");
uci.save();
fs.exec_direct('/sbin/new_cron_sync.sh');
fs.exec_direct('/etc/init.d/my_new_sms', [ 'stop' ]);
fs.exec('sleep 2');
fs.exec_direct('/etc/init.d/my_new_sms', [ 'disable' ]);
fs.exec_direct('/etc/init.d/my_new_sms', [ 'disable' ]);
if (dsled == 'D') {
fs.write('/sys/class/leds/'+led+'/brightness', '0');
}
}
}
});
});
return form.Flag.prototype.write.apply(this, [section_id, value]);
};
o = s.taboption('notifytab', form.Value, 'checktime', _('Check inbox every minute(s)'),
_('Specify how many minutes you want your inbox to be checked.'));
o.default = '10';
o.rmempty = false;
o.validate = function(section_id, value) {
if (value.match(/^[0-9]+(?:\.[0-9]+)?$/) && +value >= 5 && +value < 60)
return true;
return _('Expect a decimal value between five and fifty-nine');
};
o.datatype = 'range(5, 59)';
o = s.taboption('notifytab' , form.ListValue, 'prestart', _('Restart the inbox checking process every'),
_('The process will restart at the selected time interval. This will eliminate the delay in checking your inbox.'));
o.value('4', _('4h'));
o.value('6', _('6h'));
o.value('8', _('8h'));
o.value('12', _('12h'));
o.default = '6';
o.rmempty = false;
o = s.taboption('notifytab' , form.ListValue, 'ledtype',
_('The diode is dedicated only to these notifications'),
_("Select 'No' in case the router has only one LED or if the LED is multi-tasking. \
<br /><br /><b>Important</b> \
<br />This option requires LED to be defined in the system (if possible) to work properly. \
This requirement applies when the diode supports multiple tasks."));
o.value('S', _('No'));
o.value('D', _('Yes'));
o.default = 'D';
o.rmempty = false;
o = s.taboption('notifytab', form.ListValue, 'smsled',_('<abbr title="Light Emitting Diode">LED</abbr> Name'),
_('Select the notification LED.'));
o.load = function(section_id) {
return L.resolveDefault(fs.list('/sys/class/leds'), []).then(L.bind(function(leds) {
if(leds.length > 0) {
leds.sort((a, b) => a.name > b.name);
leds.forEach(e => o.value(e.name));
}
return this.super('load', [section_id]);
}, this));
};
o.exclude = s.section;
o.nocreate = true;
o.optional = true;
o.rmempty = true;
return m.render();
}
});