8 Commits

Author SHA1 Message Date
catarrh ce7d91cfe0 cards: From card button + normalized duplicate ICCID refusal (v2.2.18)
- The card create/edit form gets a From card button next to the ICCID
  field: it fills the field with the equipped card's EF.ICCID. It uses the
  availability model through a new 'card-iccid' requirement - enabled only
  while /api/status reports a connected card with a readable iccid; with a
  card but no readable ICCID the tooltip says so, otherwise the usual
  'insert and equip' hint applies. The last status ICCID is kept in
  _pysimCardIccid (cleared on disconnect) so the click needs no round-trip.
- Duplicate ICCID refusal now compares normalized values via
  cardsNormIccid/cardsFindDuplicateIccid (digits, spaced digits and raw EF
  hex all identify the same card), skips the row being edited, ignores an
  empty field, and names the conflicting preset in the alert (translated).
- i18n RU: From card -> 'С карты', duplicate/unreadable alerts.
- Tests: cardsFindDuplicateIccid across formats and edit-skip,
  cardsIccidFromCard fill + alert path, form wiring guards, _pysimCardIccid
  tracking in the card-state harness, card-iccid availability gating in the
  indicator harness. 261 Python + 400 frontend tests green.
- Docs: help EN+RU Cards field table, READMEs, AGENTS. SW otaman-v185.
2026-09-18 23:57:05 +03:00
catarrh 6d5d23487a cards: read EF.ICCID at equip and auto-select the matching preset (v2.2.16)
- Server: _decode_iccid (nibble-swapped E.118 digits, trailing-F pad) and
  _read_iccid (best-effort MF/2FE2 read through the parent-scoped select
  helper; the previous selection is restored, the read never raises). The
  equip path records the digit string before the TERMINAL PROFILE, i.e.
  before any CAT session is active; a startup with a card does the same.
  The value is cleared on card removal and exposed as /api/status 'iccid'
  (only while connected).
- PWA: when a connected status update reports a *new* ICCID, the matching
  card preset is selected in both SCP80 views - Secured Packet (sp-card-sel
  + form fill) and RAM (ram-card-sel + _ramCardIdx). Matching normalizes
  digits and accepts the raw EF hex form, leading zeros ignored; a manual
  choice for the same card is kept until the next equip, and a card removal
  re-arms the auto-selection. The status line shows the ICCID.
- Tests: tests/test_iccid.py (decode variants, model + probe read, equip
  recording, disconnect clearing) and frontend/tests/cards_iccid.test.js
  (normalize, find, select, no-override, card swap); the card_state test
  harness stubs the new hook and covers the guard reset.
- Docs: api.md /api/status fields, help EN+RU (SCP80 intro + Cards tab),
  READMEs, AGENTS. SW cache otaman-v183.
2026-09-18 21:05:25 +03:00
catarrh 20fbfd99a5 scp81 passthru, proactive decoders, ADM badge, file manager layout (v2.2.1)
SCP81:
- New listener mode "passthru": no local listener - the card's BIP
  channels connect straight to a configured external platform
  (host/port required), which terminates TLS and runs the dialog.
  The status API reports mode/target (_SCP81_MODE/_SCP81_TARGET) and
  clears them on stop. PWA mode select, hint, Start validation; TLS PSK
  stays the default.

Proactive command decoding (Phone tab log):
- SEND SHORT MESSAGE (0x13) is now decoded: alpha, address (TON/NPI +
  number), 3GPP-SMS TPDU (type, TP-MR, TP-DA, TP-PID 0x7F flagged as
  SIM data download, TP-DCS, TP-VP, TP-UDL), UDH concatenation IEs, and
  the TP-UD as text (GSM-7 with a septet unpacker, UCS2, 8-bit) or as a
  TS 31.115 secured packet for PID 0x7F; malformed TPDUs fall back to
  the raw hex line.
- PROVIDE LOCAL INFORMATION qualifier names completed per TS 102 223
  V18.3.0: ESN (07), MEID (0B), Supported RATs (1A); 05 relabelled
  "Reserved for GSM (Timing Advance)". Fixed in the server dict and
  both frontend tables.

Header:
- Compact ADM badge next to the card indicator: "ADM ✓" green when
  pySim's adm_verified is set, "ADM ✗" red otherwise, hidden without a
  card session or when the server is down; updated ahead of the card
  state-key early return so it never disturbs the connect/reset flow.

File manager:
- Sort pills (FID/Name), Probe all files button and progress line are
  pinned above the tree instead of scrolling with it; the tree box cap
  grows from 420px to 65vh.

SW cache otaman-v165; help EN/RU updated; tests 234 Python + 361 frontend.
2026-09-16 15:29:01 +03:00
catarrh 8459040856 ui: auto-refresh the proactive log and STK menu state
The proactive command list only re-rendered on tab/pill switches, so new
fetched commands (background STATUS polling, menu traffic) stayed
invisible while the Phone view was open.

- /api/status now exposes proactive_seq (_PROACTIVE_ENTRY_ID, monotonic
  and not reset with the log), so the existing 2s status poll detects
  changes with no extra request; pysimCardStateUpdate() re-renders the
  log when the sequence changed and the Phone/Phone view is visible
- the 5s backend timer no longer fetches the log (it was discarded) and
  now uses the already-fetched stk-status: when active/pending changes
  while the Phone tab is visible, stkCheckMenu() refreshes the menu
  button without a tab switch
- pysimProactiveLogRender() keeps its scroll position and only shows
  Loading... on a first/empty paint
- tests: proactive seq + STK signature helpers and poll-driven render
  behaviour in card_state.test.js; SW cache v123 -> v124.
2026-09-12 22:22:55 +03:00
catarrh 1fe5c6347d ui: do not show 'initializing' when no card is inserted
The message branch treated the static auto_equip config flag as if
initialization were in progress, so with auto-equip on (default) a
cardless server showed 'Card inserted — initializing...' instead of the
no-card message. The initializing state now requires equipping or an
actually present card with auto-equip enabled; regression test added.
SW cache v106 -> v107.
2026-09-12 18:09:06 +03:00
catarrh 5b9e821d6d ui: gate controls by server/card state; move Custom files to Profiler
Availability model: server-down / server-up-no-card / card-equipped.
- header shows a symbolic indicator dot (red/yellow/green, tooltip)
- a 5s probe tracks /api/version+/api/status while not fully ready; the
  2s status poll takes over once connected
- controls declare data-needs='server' or 'card'; disabled + tooltip when
  the state does not satisfy them: equip (server), status/reset, file
  manager read/save/edit, raw APDU, profile-from-card, new snapshot,
  profiler list Check card, event Send, RAM install/explore delete,
  STK menu, Send STATUS, Verify vs pySim (server), pySim execute (server),
  PLI save/poll toggle (server)
- pysimConnect no longer conflates server and card: it records both and
  Connect stays usable without a card
- ramSendOta/ramInstallCap now use pysimFetch instead of raw fetch
  (relative /api URLs broke custom server URLs)

Custom files moved from the Card reader sub-tabs to the Profiler list
tabs (Profiles / Card snapshots / Custom files); help/README/AGENTS
updated. Tests: availability gating, indicator structure, moved tab.
SW cache v103 -> v104.
2026-09-12 17:58:30 +03:00
catarrh fe10603aea server+ui: auto-equip on card insertion; reset card views on session change
- _apply_equipped_card() centralizes the post-equip refresh + TERMINAL
  PROFILE (shared by the /api/command equip branch and auto-equip)
- server tracks card_session (bumped on equip and disconnect) and
  equipping; /api/status exposes connected, card_present, card_session,
  equipping, auto_equip and is exempt from _CARD_LOCK (pure cached state)
- auto-equip is on by default (--no-auto-equip; off with --no-card-init):
  the presence observer spawns a one-shot worker after insertion, which
  runs equip under _CARD_LOCK and applies the same refresh; the monitor
  starts after the startup init so pyscard's initial 'already present'
  event does not re-equip a fresh session
- UI: /api/status polls every 2s (other views stay at 5s); when
  card_session changes it runs pysimResetCardData() (STK overlay, file
  tree, events, proactive log, PLI, status) — the same reset as a manual
  Equip; messages: initializing / press Equip / no card

Tests for the observer and auto-equip rules, session bumps,
_apply_equipped_card, and the UI state machine. SW cache v91 -> v92.
2026-09-12 13:34:40 +03:00
catarrh 57eb412b6d server+ui: detect card removal passively and reflect it within 2s
The UI only noticed a removed card when some user action ran a real card
command (e.g. Check status); /api/status is a cached-state read that kept
returning the old card, and _handle_card_disconnect() did not clear
app.card/rs.

- start_card_monitor() registers a pyscard CardObserver for our reader;
  it only polls SCardGetStatusChange (no APDU, no connection, no extra
  process), and on removal sets server.card_present=False and calls
  _handle_card_disconnect() under _CARD_LOCK
- /api/status now exposes connected (session usable) and card_present
  (physically inserted) and masks card/profile/atr/selection when not
  connected; _CARD_CONNECTED is initialized from card presence instead of
  being unconditionally True
- the 2s UI poll includes /api/status; on disconnect it switches to the
  existing 'No card detected. Insert card and click Equip' state, or the
  new 'Card inserted — press Equip' hint when the card is back; the old
  _hadData heuristic is gone

Tests for the observer (filtering, removal, insertion) and the UI state
transitions. SW cache v90 -> v91.
2026-09-12 13:21:33 +03:00