@@ -2869,6 +2917,147 @@ async function stkMenuRespond(result) {
}
}
+// ===== Cards storage =====
+let cards = [];
+
+function cardsLoad() {
+ try {
+ const d = localStorage.getItem('otaman_cards');
+ cards = d ? JSON.parse(d) : [];
+ } catch (e) { cards = []; }
+ cardsRebuildSelect();
+}
+
+function cardsSave() {
+ localStorage.setItem('otaman_cards', JSON.stringify(cards));
+ cardsRebuildSelect();
+ cardsRender();
+}
+
+function cardsAdd() {
+ const name = document.getElementById('cards-name').value.trim();
+ const iccid = document.getElementById('cards-iccid').value.trim();
+ const kic = document.getElementById('cards-kic').value.trim();
+ const kid = document.getElementById('cards-kid').value.trim();
+ const spi1 = document.getElementById('cards-spi1').value.trim();
+ const spi2 = document.getElementById('cards-spi2').value.trim();
+ const tar = document.getElementById('cards-tar').value.trim();
+ const cntr = document.getElementById('cards-cntr').value.trim();
+ const kicKey = document.getElementById('cards-kic-key').value.trim();
+ const kidKey = document.getElementById('cards-kid-key').value.trim();
+ if (!name) { alert('Name is required'); return; }
+ if (!iccid) { alert('ICCID is required'); return; }
+ if (!kic || !kid) { alert('KIc and KID are required'); return; }
+ if (!kicKey || !kidKey) { alert('KIc key and KID key are required'); return; }
+ if (cards.some(c => c.iccid === iccid)) { alert('Card with this ICCID already exists'); return; }
+ cards.push({
+ name: name,
+ iccid: iccid,
+ kic: kic,
+ kid: kid,
+ spi1: spi1 || '16',
+ spi2: spi2 || '01',
+ tar: tar,
+ cntr: cntr || '0000000001',
+ kicKey: kicKey,
+ kidKey: kidKey,
+ });
+ cardsSave();
+ ['name','iccid','kic','kid','spi1','spi2','tar','cntr','kic-key','kid-key'].forEach(id => {
+ document.getElementById('cards-' + id).value = '';
+ });
+}
+
+function cardsRemove(i) {
+ cards.splice(i, 1);
+ cardsSave();
+ cardsRender();
+}
+
+function cardsRender() {
+ const tbody = document.getElementById('cards-tbody');
+ if (!cards.length) { tbody.innerHTML = '
| No cards defined. |
'; return; }
+ let html = '';
+ for (let i = 0; i < cards.length; i++) {
+ const c = cards[i];
+ html += '';
+ html += '| ' + esc(c.name) + ' | ';
+ html += '' + esc(c.iccid) + ' | ';
+ html += '' + esc(c.kic) + ' | ';
+ html += '' + esc(c.kid) + ' | ';
+ html += '' + esc(c.spi1) + ' | ';
+ html += '' + esc(c.spi2) + ' | ';
+ html += '' + esc(c.tar || '') + ' | ';
+ html += '' + esc(c.cntr) + ' | ';
+ html += ' | ';
+ html += '
';
+ }
+ tbody.innerHTML = html;
+}
+
+function cardsRebuildSelect() {
+ const sel = document.getElementById('sp-card-sel');
+ if (!sel) return;
+ let html = '';
+ for (let i = 0; i < cards.length; i++) {
+ html += '';
+ }
+ sel.innerHTML = html;
+}
+
+function cardsApply(idx) {
+ const c = cards[parseInt(idx)];
+ if (!c) return;
+ document.getElementById('sp-spi1').value = c.spi1;
+ document.getElementById('sp-spi2-hex').value = c.spi2;
+ document.getElementById('sp-kic-hex').value = c.kic;
+ document.getElementById('sp-kid-hex').value = c.kid;
+ document.getElementById('sp-cntr').value = c.cntr;
+ document.getElementById('sp-kic-key').value = c.kicKey;
+ document.getElementById('sp-kid-key').value = c.kidKey;
+ updateSp();
+ genSp();
+}
+
+function cardsExport() {
+ const el = document.getElementById('cards-io');
+ el.value = JSON.stringify(cards, null, 2);
+ el.classList.remove('hidden');
+ el.select();
+}
+
+function cardsImport() {
+ const el = document.getElementById('cards-io');
+ try {
+ const imported = JSON.parse(el.value);
+ if (!Array.isArray(imported)) throw new Error('Expected an array');
+ let added = 0;
+ for (const entry of imported) {
+ if (!entry.name || !entry.iccid) continue;
+ if (cards.some(c => c.iccid === entry.iccid)) continue;
+ cards.push({
+ name: entry.name,
+ iccid: entry.iccid,
+ kic: entry.kic || '15',
+ kid: entry.kid || '15',
+ spi1: entry.spi1 || '16',
+ spi2: entry.spi2 || '01',
+ tar: entry.tar || '',
+ cntr: entry.cntr || '0000000001',
+ kicKey: entry.kicKey || '',
+ kidKey: entry.kidKey || '',
+ });
+ added++;
+ }
+ cardsSave();
+ cardsRender();
+ el.value = 'Imported ' + added + ' cards.';
+ setTimeout(() => { el.classList.add('hidden'); }, 2000);
+ } catch (e) {
+ alert('Import error: ' + e.message);
+ }
+}
+
// ===== pysim sub-tabs =====
let pysimCmdHistory = [];
let pysimCmdHistIdx = -1;
@@ -3450,6 +3639,9 @@ function pysimCustomImport() {
// Init custom files
pysimCustomLoad();
+// Init cards
+cardsLoad();
+
// Init sub-tab pills
document.querySelectorAll('.pysim-subtab').forEach(btn => {
btn.addEventListener('click', () => pysimSwitchSubtab(btn.dataset.pysimSub));
diff --git a/style.css b/style.css
index d26f903..7a54502 100644
--- a/style.css
+++ b/style.css
@@ -663,6 +663,10 @@ video {
display: flex;
}
+.table {
+ display: table;
+}
+
.grid {
display: grid;
}
@@ -847,6 +851,10 @@ video {
overflow: auto;
}
+.overflow-x-auto {
+ overflow-x: auto;
+}
+
.overflow-y-auto {
overflow-y: auto;
}
@@ -892,6 +900,11 @@ video {
border-top-width: 1px;
}
+.border-gray-100 {
+ --tw-border-opacity: 1;
+ border-color: rgb(243 244 246 / var(--tw-border-opacity, 1));
+}
+
.border-gray-200 {
--tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));
@@ -1049,6 +1062,10 @@ video {
padding-top: 0.75rem;
}
+.text-left {
+ text-align: left;
+}
+
.text-center {
text-align: center;
}