Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions QLog.pro
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ SOURCES += \
service/lotw/Lotw.cpp \
service/potaapp/PotaApp.cpp \
service/qrzcom/QRZ.cpp \
service/qslinfo/QSLInfo.cpp \
ui/ActivityEditor.cpp \
ui/AdifRecoveryManager.cpp \
ui/AlertRuleDetail.cpp \
Expand Down Expand Up @@ -375,6 +376,7 @@ HEADERS += \
service/lotw/Lotw.h \
service/potaapp/PotaApp.h \
service/qrzcom/QRZ.h \
service/qslinfo/QSLInfo.h \
ui/ActivityEditor.h \
ui/AdifRecoveryManager.h \
ui/AlertRuleDetail.h \
Expand Down
195 changes: 179 additions & 16 deletions core/CallbookManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "core/debug.h"
#include "service/hamqth/HamQTH.h"
#include "service/qrzcom/QRZ.h"
#include "service/qslinfo/QSLInfo.h"
#include "data/Callsign.h"
#include "LogParam.h"

Expand All @@ -11,7 +12,9 @@ MODULE_IDENTIFICATION("qlog.ui.callbookmanager");
CallbookManager::CallbookManager(QObject *parent)
: QObject{parent},
primaryCallbookAuthSuccess(false),
secondaryCallbookAuthSuccess(false)
secondaryCallbookAuthSuccess(false),
pendingCallbookResultAvailable(false),
waitingForQSLInfo(false)
{
FCT_IDENTIFICATION;

Expand All @@ -34,12 +37,18 @@ void CallbookManager::queryCallsign(const QString &callsign)
// if there is the second query for the same call immediately after
// the first query, then it returns a result of empty object
queryCache.insert(callsign, new CallbookResponseData);
currentQueryCallsign = callsign;

if ( !primaryCallbook.isNull() )
{
currentQueryCallsign = callsign;
primaryCallbook->queryCallsign(currentQueryCallsign);
}
else if ( !qslInfoCallbook.isNull() )
{
CallbookResponseData data;
data.call = callsign;
requestQSLInfo(data, false);
}
else
{
queryCache.remove(callsign);
Expand All @@ -51,7 +60,9 @@ bool CallbookManager::isActive()
{
FCT_IDENTIFICATION;

bool ret = primaryCallbookAuthSuccess || secondaryCallbookAuthSuccess;
bool ret = primaryCallbookAuthSuccess
|| secondaryCallbookAuthSuccess
|| !qslInfoCallbook.isNull();
qCDebug(runtime) << ret;
return ret;
}
Expand Down Expand Up @@ -81,16 +92,30 @@ GenericCallbook *CallbookManager::createCallbook(const QString &callbookID)

void CallbookManager::initCallbooks()
{
primaryCallbook.clear();
secondaryCallbook.clear();
FCT_IDENTIFICATION;

disposeCallbook(primaryCallbook);
disposeCallbook(secondaryCallbook);
disposeCallbook(qslInfoCallbook);

primaryCallbookAuthSuccess = false;
secondaryCallbookAuthSuccess = false;
pendingCallbookData = CallbookResponseData();
pendingCallbookResultAvailable = false;
waitingForQSLInfo = false;

queryCache.clear();
currentQueryCallsign = QString();

primaryCallbook = createCallbook(LogParam::getPrimaryCallbook(GenericCallbook::CALLBOOK_NAME));
secondaryCallbook = createCallbook(LogParam::getSecondaryCallbook(GenericCallbook::CALLBOOK_NAME));
if ( LogParam::getQSLInfoCallbookEnabled() )
qslInfoCallbook = new QSLInfoCallbook(this);

qCDebug(runtime) << "Initializing callbooks"
<< "primary" << (primaryCallbook ? primaryCallbook->getDisplayName() : QStringLiteral("disabled"))
<< "secondary" << (secondaryCallbook ? secondaryCallbook->getDisplayName() : QStringLiteral("disabled"))
<< "QSLInfo.de" << !qslInfoCallbook.isNull();

if ( !primaryCallbook.isNull() )
{
Expand Down Expand Up @@ -125,6 +150,16 @@ void CallbookManager::initCallbooks()
});
secondaryCallbookAuthSuccess = true;
}

if ( !qslInfoCallbook.isNull() )
{
connect(qslInfoCallbook, &GenericCallbook::callsignResult,
this, &CallbookManager::processQSLInfoResult);
connect(qslInfoCallbook, &GenericCallbook::callsignNotFound,
this, &CallbookManager::qslInfoCallsignNotFound);
connect(qslInfoCallbook, &GenericCallbook::lookupError,
this, &CallbookManager::qslInfoLookupError);
}
}

void CallbookManager::abortQuery()
Expand All @@ -134,6 +169,10 @@ void CallbookManager::abortQuery()
queryCache.remove(currentQueryCallsign);
if ( ! primaryCallbook.isNull() ) primaryCallbook->abortQuery();
if ( ! secondaryCallbook.isNull() ) secondaryCallbook->abortQuery();
if ( ! qslInfoCallbook.isNull() ) qslInfoCallbook->abortQuery();
pendingCallbookData = CallbookResponseData();
pendingCallbookResultAvailable = false;
waitingForQSLInfo = false;
}

void CallbookManager::primaryCallbookCallsignNotFound(const QString &notFoundCallsign)
Expand All @@ -148,7 +187,7 @@ void CallbookManager::primaryCallbookCallsignNotFound(const QString &notFoundCal

if ( secondaryCallbook.isNull() )
{
emit callsignNotFound(notFoundCallsign);
completeCallsignNotFound(notFoundCallsign);
return;
}

Expand All @@ -169,21 +208,17 @@ void CallbookManager::secondaryCallbookCallsignNotFound(const QString &notFoundC

qCDebug(runtime) << "Callsign not found - secondary ";

emit callsignNotFound(notFoundCallsign);
completeCallsignNotFound(notFoundCallsign);
}

void CallbookManager::processCallsignResult(const CallbookResponseData &data)
{
FCT_IDENTIFICATION;

CallbookResponseData *cacheData = new CallbookResponseData;
*cacheData = data;
queryCache.insert(data.call, cacheData);

// Callbook returned queried callsign
if ( data.call == currentQueryCallsign )
{
emit callsignResult(data);
requestQSLInfo(data, true);
return;
}

Expand Down Expand Up @@ -217,12 +252,140 @@ void CallbookManager::processCallsignResult(const CallbookResponseData &data)
newData.nick = data.nick;
newData.image_url = data.image_url;

CallbookResponseData *cdata = new CallbookResponseData;
*cdata = newData;
requestQSLInfo(newData, true);
}
}

void CallbookManager::requestQSLInfo(const CallbookResponseData &data,
bool baseResultAvailable)
{
FCT_IDENTIFICATION;

qCDebug(function_parameters) << data.call << baseResultAvailable;

if ( qslInfoCallbook.isNull() )
{
if ( baseResultAvailable )
completeCallsignResult(data);
else
completeCallsignNotFound(data.call);
return;
}

pendingCallbookData = data;
pendingCallbookResultAvailable = baseResultAvailable;
waitingForQSLInfo = true;

queryCache.insert(currentQueryCallsign, cdata);
emit callsignResult(newData);
qCDebug(runtime) << "Querying QSLInfo.de supplemental QSL manager for"
<< currentQueryCallsign;
qslInfoCallbook->queryCallsign(currentQueryCallsign);
}

void CallbookManager::processQSLInfoResult(const CallbookResponseData &data)
{
FCT_IDENTIFICATION;

qCDebug(function_parameters) << data.call << data.qsl_via;

if ( !waitingForQSLInfo || data.call != currentQueryCallsign )
{
qCDebug(runtime) << "Ignoring stale QSLInfo.de result for" << data.call;
return;
}

if ( !data.qsl_via.isEmpty() )
{
qCDebug(runtime) << "QSLInfo.de overrides QSL Via for"
<< currentQueryCallsign << data.qsl_via;
pendingCallbookData.qsl_via = data.qsl_via;
pendingCallbookData.qsl_via_override = true;
}

pendingCallbookData.call = currentQueryCallsign;
const CallbookResponseData result = pendingCallbookData;
waitingForQSLInfo = false;
pendingCallbookResultAvailable = false;
pendingCallbookData = CallbookResponseData();
completeCallsignResult(result);
}

void CallbookManager::qslInfoCallsignNotFound(const QString &callsign)
{
FCT_IDENTIFICATION;

qCDebug(function_parameters) << callsign;

if ( !waitingForQSLInfo || callsign != currentQueryCallsign )
return;

const bool baseResultAvailable = pendingCallbookResultAvailable;
const CallbookResponseData result = pendingCallbookData;
waitingForQSLInfo = false;
pendingCallbookResultAvailable = false;
pendingCallbookData = CallbookResponseData();

if ( baseResultAvailable )
completeCallsignResult(result);
else
{
queryCache.remove(callsign);
emit callsignNotFound(callsign);
}
}

void CallbookManager::qslInfoLookupError(const QString &error)
{
FCT_IDENTIFICATION;

qCWarning(runtime) << "QSLInfo.de supplemental lookup failed" << error;

// A supplemental service outage must not discard or interrupt a valid
// result from the primary/secondary callbook. Surface the error only when
// QSLInfo.de is the sole provider for this lookup.
if ( !pendingCallbookResultAvailable )
emit lookupError(QStringLiteral("QSLInfo.de - ") + error);

qslInfoCallsignNotFound(currentQueryCallsign);
}

void CallbookManager::completeCallsignResult(const CallbookResponseData &data)
{
FCT_IDENTIFICATION;

CallbookResponseData *cacheData = new CallbookResponseData;
*cacheData = data;
queryCache.insert(data.call, cacheData);
emit callsignResult(data);
}

void CallbookManager::completeCallsignNotFound(const QString &callsign)
{
FCT_IDENTIFICATION;

queryCache.remove(callsign);

if ( !qslInfoCallbook.isNull() )
{
CallbookResponseData data;
data.call = callsign;
requestQSLInfo(data, false);
return;
}

emit callsignNotFound(callsign);
}

void CallbookManager::disposeCallbook(QPointer<GenericCallbook> &callbook)
{
FCT_IDENTIFICATION;

if ( callbook.isNull() )
return;

disconnect(callbook, nullptr, this, nullptr);
callbook->abortQuery();
callbook->deleteLater();
callbook.clear();
}

QCache<QString, CallbookResponseData> CallbookManager::queryCache(100);
12 changes: 12 additions & 0 deletions core/CallbookManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,27 @@ private slots:
void primaryCallbookCallsignNotFound(const QString&);
void secondaryCallbookCallsignNotFound(const QString&);
void processCallsignResult(const CallbookResponseData &data);
void processQSLInfoResult(const CallbookResponseData &data);
void qslInfoCallsignNotFound(const QString &callsign);
void qslInfoLookupError(const QString &error);

private:
GenericCallbook *createCallbook(const QString&);
void requestQSLInfo(const CallbookResponseData &data,
bool baseResultAvailable);
void completeCallsignResult(const CallbookResponseData &data);
void completeCallsignNotFound(const QString &callsign);
void disposeCallbook(QPointer<GenericCallbook> &callbook);

private:
QPointer<GenericCallbook> primaryCallbook;
bool primaryCallbookAuthSuccess;
QPointer<GenericCallbook> secondaryCallbook;
bool secondaryCallbookAuthSuccess;
QPointer<GenericCallbook> qslInfoCallbook;
CallbookResponseData pendingCallbookData;
bool pendingCallbookResultAvailable;
bool waitingForQSLInfo;
QString currentQueryCallsign;
static QCache<QString, CallbookResponseData> queryCache;

Expand Down
10 changes: 10 additions & 0 deletions core/LogParam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,16 @@ void LogParam::setSecondaryCallbook(const QString &callbookName)
setParam("callbook/secondary", callbookName);
}

bool LogParam::getQSLInfoCallbookEnabled()
{
return getParam("callbook/qslinfo/enabled", false).toBool();
}

void LogParam::setQSLInfoCallbookEnabled(bool enabled)
{
setParam("callbook/qslinfo/enabled", enabled);
}

QString LogParam::getCallbookWebLookupURL(const QString &defaultURL)
{
return getParam("callbook/weblookupurl", defaultURL).toString();
Expand Down
2 changes: 2 additions & 0 deletions core/LogParam.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ class LogParam : public QObject
static void setPrimaryCallbook(const QString& callbookName);
static QString getSecondaryCallbook(const QString &defaultValue);
static void setSecondaryCallbook(const QString& callbookName);
static bool getQSLInfoCallbookEnabled();
static void setQSLInfoCallbookEnabled(bool enabled);
static QString getCallbookWebLookupURL(const QString &defaultURL);
static void setCallbookWebLookupURL(const QString& url);

Expand Down
3 changes: 3 additions & 0 deletions service/GenericCallbook.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ struct CallbookResponseData
QString qth;
QString gridsquare;
QString qsl_via;
// True when a supplemental service explicitly requested replacement of
// the existing QSL Via value instead of the usual fill-if-empty behavior.
bool qsl_via_override = false;
QString cqz;
QString ituz;
QString dok;
Expand Down
Loading