chore: release v0.21.3
This commit is contained in:
+28
-7
@@ -36,8 +36,8 @@ func DownloadLoTWConfirmations(ctx context.Context, client *http.Client, cfg Ser
|
||||
q.Set("login", user)
|
||||
q.Set("password", cfg.Password)
|
||||
q.Set("qso_query", "1")
|
||||
q.Set("qso_qsl", "yes") // only QSLed (confirmed) records
|
||||
q.Set("qso_qsldetail", "yes") // include QSL_RCVD / QSLRDATE detail
|
||||
q.Set("qso_qsl", "yes") // only QSLed (confirmed) records
|
||||
q.Set("qso_qsldetail", "yes") // include QSL_RCVD / QSLRDATE detail
|
||||
if c := strings.TrimSpace(ownCall); c != "" {
|
||||
q.Set("qso_owncall", c) // restrict to this station callsign
|
||||
}
|
||||
@@ -65,11 +65,32 @@ func DownloadLoTWConfirmations(ctx context.Context, client *http.Client, cfg Ser
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("lotw: http %d", resp.StatusCode)
|
||||
}
|
||||
// LoTW returns a plain-text error (not ADIF) on bad login.
|
||||
// Not ADIF. Two very different failures land here, and telling them apart is
|
||||
// the difference between a fixable message and a wall of markup.
|
||||
if !strings.Contains(strings.ToUpper(text), "<EOH>") && !strings.Contains(strings.ToLower(text), "<eor>") {
|
||||
msg := strings.TrimSpace(text)
|
||||
trimmed := strings.TrimSpace(text)
|
||||
// Keep the whole thing in the log — that is where a real diagnosis happens,
|
||||
// and a 200-character excerpt of an HTML page tells nobody anything.
|
||||
snippet := trimmed
|
||||
if len(snippet) > 2000 {
|
||||
snippet = snippet[:2000]
|
||||
}
|
||||
LogSink("lotw: expected ADIF, got %d bytes of non-ADIF; first 2000: %s", len(text), snippet)
|
||||
|
||||
// LoTW answers a REJECTED LOGIN with its ordinary web page rather than an
|
||||
// error string, so an HTML body here means the credentials were not
|
||||
// accepted — not that the download is broken.
|
||||
lower := strings.ToLower(trimmed)
|
||||
if strings.HasPrefix(lower, "<!doctype html") || strings.HasPrefix(lower, "<html") || strings.Contains(lower, "logbook of the world</title>") {
|
||||
return "", fmt.Errorf("LoTW returned its web page instead of a log, which is how it answers a login it did not accept. " +
|
||||
"Check the username and password in Settings → External services: LoTW wants your lotw.arrl.org WEBSITE login, " +
|
||||
"not your callsign certificate or your ARRL member number")
|
||||
}
|
||||
|
||||
// Anything else: a plain-text complaint from LoTW, or a maintenance notice.
|
||||
msg := trimmed
|
||||
if len(msg) > 200 {
|
||||
msg = msg[:200]
|
||||
msg = msg[:200] + "…"
|
||||
}
|
||||
return "", fmt.Errorf("lotw: unexpected response: %s", msg)
|
||||
}
|
||||
@@ -220,8 +241,8 @@ func UploadLoTW(ctx context.Context, cfg ServiceConfig, tempDir, adifRecord stri
|
||||
// AppCompat RUNASADMIN entry), but OpsLog isn't elevated so Windows
|
||||
// refuses to launch it. Actionable message instead of the raw error.
|
||||
return UploadResult{}, fmt.Errorf(
|
||||
"lotw: Windows won't launch tqsl.exe because it's marked \"Run as administrator\". " +
|
||||
"Fix: right-click %q → Properties → Compatibility → UNTICK \"Run this program as an administrator\" (Apply). " +
|
||||
"lotw: Windows won't launch tqsl.exe because it's marked \"Run as administrator\". "+
|
||||
"Fix: right-click %q → Properties → Compatibility → UNTICK \"Run this program as an administrator\" (Apply). "+
|
||||
"Or run OpsLog itself as administrator.", tqsl)
|
||||
} else {
|
||||
return UploadResult{}, fmt.Errorf("lotw: run tqsl: %w", runErr)
|
||||
|
||||
Reference in New Issue
Block a user