up
This commit is contained in:
@@ -125,6 +125,32 @@ func (m *Manager) Lookup(ctx context.Context, callsign string) (Result, error) {
|
||||
lastErr = fmt.Errorf("%s: %w", p.Name(), err)
|
||||
}
|
||||
|
||||
// Portable / slashed call not found under its full form: the operator's
|
||||
// record lives under the HOME call (JW/OR1A → OR1A, DL/F4NIE → F4NIE). Look
|
||||
// THAT up for the name/QTH/QSL info, then overwrite the location-determining
|
||||
// fields with the SLASHED call's entity (JW = Svalbard, not OR1A's Belgium).
|
||||
if home := homeCall(call); home != "" && home != call {
|
||||
for _, p := range providers {
|
||||
r, err := p.Lookup(ctx, home)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
r.Callsign = call
|
||||
r.Source = p.Name()
|
||||
r.FetchedAt = time.Now().UTC()
|
||||
// The home record's location is the operator's HOME, not where they
|
||||
// are portable now — clear it so cty.dat fills the real entity.
|
||||
r.Country, r.Continent = "", ""
|
||||
r.CQZ, r.ITUZ, r.DXCC = 0, 0, 0
|
||||
r.Lat, r.Lon = 0, 0
|
||||
r.Grid, r.State, r.County = "", "", ""
|
||||
fillFromDXCC(&r, dxcc) // entity/zones/lat-lon from the FULL (slashed) call
|
||||
normalizeNames(&r)
|
||||
_ = m.cache.Put(ctx, r)
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
// All providers exhausted (not-found or errored). Try the cty.dat
|
||||
// resolver as a last resort — at least we can hand back country/zones
|
||||
// even for unknown callsigns. Not cached: a "cty.dat-only" result
|
||||
@@ -149,6 +175,29 @@ func (m *Manager) Lookup(ctx context.Context, callsign string) (Result, error) {
|
||||
return Result{}, lastErr
|
||||
}
|
||||
|
||||
// homeCall extracts the operator's home callsign from a slashed/portable call
|
||||
// so its provider record (name/QTH/QSL) can be fetched when the full form isn't
|
||||
// registered: JW/OR1A → OR1A, DL/F4NIE → F4NIE, F4BPO/P → F4BPO, VP8/F4BPO →
|
||||
// F4BPO. The home call is the "/"-part that looks like a real callsign (has a
|
||||
// digit, ≥3 chars); the longest such part wins (handles PREFIX/HOMECALL where
|
||||
// both could qualify, e.g. VP8/F4BPO). Returns "" if none qualifies.
|
||||
func homeCall(call string) string {
|
||||
if !strings.ContainsRune(call, '/') {
|
||||
return call
|
||||
}
|
||||
best := ""
|
||||
for _, p := range strings.Split(call, "/") {
|
||||
p = strings.TrimSpace(p)
|
||||
if len(p) < 3 || !strings.ContainsAny(p, "0123456789") {
|
||||
continue // a prefix (JW, DL) or a suffix (P, M, MM, QRP, a digit)
|
||||
}
|
||||
if len(p) > len(best) {
|
||||
best = p
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
||||
// normalizeNames title-cases the human-readable text fields so a QRZ/HamQTH
|
||||
// reply in ALL CAPS ("NOEL CHENAVARD", "VETRAZ-MONTHOUX") is stored and shown
|
||||
// consistently ("Noel Chenavard", "Vetraz-Monthoux"). State/zones/grid are
|
||||
|
||||
Reference in New Issue
Block a user