From 92ee8aaddeb60dde7658aeddb339bd3e8dcabd01 Mon Sep 17 00:00:00 2001 From: Gregory Salaun Date: Wed, 5 Aug 2026 10:45:58 +0200 Subject: [PATCH] fix(entry): stop stray QSO logging from freq-Enter and bare-number DX call Two ways a bogus contact could be logged: - Enter in the TX/RX frequency field bubbled to the entry container's onKeyDown, which calls save() on Enter-in-an-input. Typing a frequency and pressing Enter tuned the rig AND logged the QSO. The freq fields now stopPropagation so Enter only tunes. - WSJT-X/JTDX broadcasts its DX-call field over UDP; when it holds a bare number ("1"), applyUdpCall dropped it into the callsign, and the next Enter logged a QSO with callsign "1". Reject any DX call with no letter. --- changelog.json | 6 ++++-- frontend/src/App.tsx | 9 +++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.json b/changelog.json index 30ea8bb..1f29984 100644 --- a/changelog.json +++ b/changelog.json @@ -7,14 +7,16 @@ "Ultrabeam over a remote link: fixed intermittent connection drops, phantom frequency jumps and wrong element-length readings. On a slow link a command that timed out left its late reply in the stream, and the next command read it as its own — crossing a status query with an element-length one, for instance. The stream is now flushed of any stale reply before each command, keeping the exchange in step.", "Ultrabeam: the 'moving' indicator and the Flex TX-inhibit now react the instant you click a band or pattern, instead of up to a status poll (~2 s) later. A commanded move reports motion immediately; the real motor state takes over once the next poll reads it.", "CAT sharing (FT8): JTDX/WSJT-X transmit correctly again through OpsLog's shared rig. get_ptt now echoes the PTT state the client last commanded — clients poll it DURING transmit to confirm the rig is keyed, and OpsLog always answering 'receiving' made them give up and drop the over after a second or two. The 0.23.5 'Fake It' anti-drift tweak was also reverted (it had made this total — no transmit at all); the small dial creep in 'Fake It' split can return, and JTDX's 'Split Operation: None' avoids it.", - "CAT settings: trimmed the long help text under the Kenwood and CAT-sharing fields down to the essentials — less clutter." + "CAT settings: trimmed the long help text under the Kenwood and CAT-sharing fields down to the essentials — less clutter.", + "Entry form: fixed two ways a stray QSO could sneak in. Pressing Enter in the TX/RX frequency field now only tunes the radio — it was also submitting the contact. And a bare number with no letter (JTDX/WSJT-X sometimes broadcasts \"1\" as the DX call) is no longer accepted into the callsign field, where it could get logged as callsign \"1\"." ], "fr": [ "Visionneuse de log : la fenêtre conserve deux fois plus d'historique (512 Ko au lieu de 256 Ko, ~3200 lignes). Lors d'une trace chargée, les plus vieilles lignes défilaient hors du buffer pendant qu'on les lisait encore ; la fenêtre agrandie les garde.", "Ultrabeam en remote : coupures de connexion intermittentes, sauts de fréquence fantômes et longueurs d'éléments erronées corrigés. Sur un lien lent, une commande qui expirait laissait sa réponse tardive dans le flux, et la commande suivante la lisait comme la sienne — croisant par exemple une requête de statut avec une requête de longueurs d'éléments. Le flux est désormais vidé de toute réponse périmée avant chaque commande, gardant l'échange synchronisé.", "Ultrabeam : l'indicateur « en mouvement » et l'inhibition d'émission Flex réagissent désormais dès que vous cliquez sur une bande ou un diagramme, au lieu d'attendre jusqu'à un poll de statut (~2 s). Un mouvement commandé signale le déplacement immédiatement ; l'état réel des moteurs prend le relais dès le poll suivant.", "Partage CAT (FT8) : JTDX/WSJT-X émettent de nouveau correctement via la radio partagée d'OpsLog. get_ptt renvoie désormais l'état PTT commandé en dernier par le client — les clients l'interrogent PENDANT l'émission pour confirmer que la radio est en émission, et comme OpsLog répondait toujours « réception », ils abandonnaient et coupaient l'émission au bout d'une seconde ou deux. L'ajustement anti-drift « Fake It » de la 0.23.5 a aussi été annulé (il rendait le problème total — aucune émission) ; le léger glissement du VFO en split « Fake It » peut réapparaître, et « Split Operation : None » dans JTDX l'évite.", - "Réglages CAT : textes d'aide raccourcis sous les champs Kenwood et partage CAT — moins de fouillis." + "Réglages CAT : textes d'aide raccourcis sous les champs Kenwood et partage CAT — moins de fouillis.", + "Formulaire de saisie : deux façons de logguer un QSO parasite corrigées. Appuyer sur Entrée dans le champ fréquence TX/RX ne fait plus que syntoniser la radio — cela validait aussi le contact. Et un nombre nu sans lettre (JTDX/WSJT-X diffuse parfois « 1 » comme DX call) n'est plus accepté dans le champ indicatif, où il pouvait être loggué comme indicatif « 1 »." ] }, { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f4d757f..30913c0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2607,6 +2607,11 @@ export default function App() { const applyUdpCall = (raw: string, force = false): boolean => { const call = String(raw ?? '').trim(); if (!call) return false; + // A callsign always has at least one letter. WSJT-X/JTDX (and relayed spot + // clicks) sometimes broadcast a bare number in the DX-call field — famously + // "1" — which would land in the entry and, on the next Enter, log a QSO + // with callsign "1". Reject anything with no letter. + if (!/[a-z]/i.test(call)) return false; const upper = call.toUpperCase(); const current = callsignValRef.current.trim().toUpperCase(); const prev = lastUdpCallRef.current; @@ -4355,7 +4360,7 @@ export default function App() { title={catState.connected ? t('field.freqTuneHint') : undefined} onFocus={() => setFreqFocused(true)} onBlur={() => setFreqFocused(false)} - onKeyDown={(e) => { if (e.key === 'Enter') tuneRadioTo(freqMhz); }} + onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); e.stopPropagation(); tuneRadioTo(freqMhz); } }} onChange={(e) => { setFreqMhz(e.target.value); noteManualEdit(); const b = bandForMHz(parseFloat(e.target.value)); if (b) setBand(b); }} /> @@ -4370,7 +4375,7 @@ export default function App() { title={catState.connected ? t('field.freqTuneHint') : undefined} onFocus={() => setFreqFocused(true)} onBlur={() => setFreqFocused(false)} - onKeyDown={(e) => { if (e.key === 'Enter') tuneRadioTo(rxFreqMhz); }} + onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); e.stopPropagation(); tuneRadioTo(rxFreqMhz); } }} onChange={(e) => { setRxFreqMhz(e.target.value); noteManualEdit(); const rb = bandForMHz(parseFloat(e.target.value)); if (rb) setBandRx(rb); }} className={cn('font-mono', catState.split && 'bg-danger-muted/40 border-danger-border focus:bg-card')} />