From 305da583e1e123ae580b23b5b64ba0c2f91881aa Mon Sep 17 00:00:00 2001 From: rouggy Date: Tue, 28 Jul 2026 15:43:47 +0200 Subject: [PATCH] fix: QRZ download used an option QRZ does not accept MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The date window was sent as OPTION=AFTER:. That was a guess, and QRZ rejects the request outright — RESULT=FAIL with no reason — so the confirmation download failed completely for everyone, whatever the account. The documented option is MODSINCE, and it is the better window anyway: it selects records MODIFIED since the date, so a QSO from years ago that was confirmed yesterday comes back. A QSO-date window structurally cannot return those, and confirmations are the whole point of this download — which is why the client-side date filter is now skipped when the server did the windowing, instead of throwing those same records away on arrival. A refusal now falls back to ALL rather than leaving the operator with nothing. --- app.go | 26 ++++++++++++++++++++++---- changelog.json | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app.go b/app.go index 79d578a..8e27bd6 100644 --- a/app.go +++ b/app.go @@ -9576,7 +9576,7 @@ func (a *App) runDownloadConfirmations(svc extsvc.Service, cfg extsvc.ExternalSe sinceDate := resolveSince(keyExtQRZLastDownload) emit(fmt.Sprintf("Window: since=%q → resolved date=%q (key %s%s)", since, sinceDate, a.profileScope(), keyExtQRZLastDownload)) if sinceDate != "" { - emit("Fetching QRZ.com logbook (will skip QSOs before " + sinceDate + ")…") + emit("Fetching QRZ.com logbook (records modified since " + sinceDate + ")…") } else { emit("Fetching QRZ.com logbook (full — no since date)…") } @@ -9585,11 +9585,26 @@ func (a *App) runDownloadConfirmations(svc extsvc.Service, cfg extsvc.ExternalSe // truncates mid-record, so the parse died two thirds of the way through // and everything past that point was never seen. AFTER: narrows it at the // source; the client-side date filter below stays as the backstop. - fetchOpt := "ALL" + // + // The option is MODSINCE (QRZ FETCH documentation) — "AFTER:" was a guess + // and QRZ rejected the whole fetch, which broke the download outright. + // MODSINCE is also the RIGHT window for this job: it selects records + // MODIFIED since the date, so a ten-year-old QSO confirmed yesterday comes + // back — a QSO-date window would never return it, and confirmations are + // exactly what this download is for. + // + // It stays an optimisation, never a requirement: if QRZ refuses it, fall + // back to ALL rather than leaving the operator with no download at all. + fetchOpt, serverWindowed := "ALL", false if sinceDate != "" { - fetchOpt = "AFTER:" + sinceDate + fetchOpt, serverWindowed = "MODSINCE:"+sinceDate, true } fr, err := extsvc.FetchQRZ(ctx, nil, cfg.QRZ.APIKey, fetchOpt) + if err != nil && serverWindowed { + emit("QRZ.com refused MODSINCE (" + err.Error() + ") — fetching the full logbook instead…") + fetchOpt, serverWindowed = "ALL", false + fr, err = extsvc.FetchQRZ(ctx, nil, cfg.QRZ.APIKey, fetchOpt) + } if err != nil { emit("Fetch failed: " + err.Error()) done(matched, total) @@ -9649,7 +9664,10 @@ func (a *App) runDownloadConfirmations(svc extsvc.Service, cfg extsvc.ExternalSe return nil } // Date window (client-side): skip QSOs older than the requested date. - if sinceDate != "" && !q.QSODate.IsZero() && q.QSODate.UTC().Format("2006-01-02") < sinceDate { + // ONLY when the server did not window the fetch itself — MODSINCE + // returns old QSOs whose CONFIRMATION is recent, and filtering those + // out by QSO date would throw away the very records asked for. + if !serverWindowed && sinceDate != "" && !q.QSODate.IsZero() && q.QSODate.UTC().Format("2006-01-02") < sinceDate { return nil } // Skip a QSO logged under a DIFFERENT one of the operator's callsigns. diff --git a/changelog.json b/changelog.json index ca12901..131a2a1 100644 --- a/changelog.json +++ b/changelog.json @@ -4,10 +4,12 @@ "date": "2026-07-28", "en": [ "Microwave bands are recognised: 13cm, 9cm, 6cm, 3cm (10 GHz), 1.25cm and above, plus 33cm and the 2190m/630m/560m low bands. A 10 GHz QSO used to come back with NO band at all — so it was logged without one, counted in no award slot, and exported without a BAND field. Band pickers, statistics and award band columns follow.", + "QRZ.com confirmation download works again: the date window used an option QRZ rejects, so every fetch failed. It now uses MODSINCE, which also returns older QSOs confirmed recently.", "Port fields can be cleared. Deleting the contents put the default straight back, so entering a different port meant overwriting it digit by digit. Fixed on the cluster editor, where it was reported, and in the eight other places with the same fault (CAT, amplifier, antenna, rotator, database, SMTP)." ], "fr": [ "Les bandes hyperfréquences sont reconnues : 13cm, 9cm, 6cm, 3cm (10 GHz), 1.25cm et au-delà, ainsi que 33cm et les bandes basses 2190m/630m/560m. Un QSO à 10 GHz revenait sans AUCUNE bande — donc enregistré sans bande, compté dans aucun diplôme, et exporté sans champ BAND. Les listes de bandes, les statistiques et les colonnes de diplômes suivent.", + "Le téléchargement des confirmations QRZ.com refonctionne : la fenêtre de date utilisait une option refusée par QRZ, donc chaque récupération échouait. Elle utilise désormais MODSINCE, qui renvoie aussi les QSO anciens confirmés récemment.", "Les champs de port peuvent être vidés. Effacer le contenu réinscrivait aussitôt la valeur par défaut, si bien qu'entrer un autre port obligeait à l'écraser chiffre par chiffre. Corrigé dans l'éditeur de cluster, où c'était signalé, et dans les huit autres endroits présentant le même défaut (CAT, amplificateur, antenne, rotator, base de données, SMTP)." ] },