Merge branch 'fix/oidc' into 'release/6.2'

fetch config without restarting app

See merge request BC/public/linphone-desktop!1802
This commit is contained in:
Gaëlle Braud 2026-04-08 15:03:06 +00:00
commit 1481d3acea
7 changed files with 152 additions and 110 deletions

View file

@ -341,6 +341,19 @@ App::App(int &argc, char *argv[])
mOIDCRefreshTimer.setInterval(1000);
mOIDCRefreshTimer.setSingleShot(false);
connect(this, &App::restartCoreRequested, this, [this] {
initCore();
if (mCliModelConnection) mCliModelConnection->disconnect();
if (mCoreModelConnection) {
mCoreModelConnection->disconnect();
mCoreModelConnection->setModel(CoreModel::getInstance());
}
// reset connections with the new CoreModel
resetConnections();
sendCommand(false);
setIsRestarting(false);
});
#ifdef Q_OS_LINUX
exportDesktopFile();
#endif
@ -349,10 +362,16 @@ App::App(int &argc, char *argv[])
App::~App() {
}
void App::setSelf(QSharedPointer<App>(me)) {
mCoreModelConnection = SafeConnection<App, CoreModel>::create(me, CoreModel::getInstance());
void App::resetConnections() {
connectCoreModel();
connectCliModel();
}
void App::connectCoreModel() {
Q_ASSERT(mCoreModelConnection);
mCoreModelConnection->makeConnectToModel(&CoreModel::callCreated,
[this](const std::shared_ptr<linphone::Call> &call) {
lDebug() << "Call created in core, get calls window";
if (call->getDir() == linphone::Call::Dir::Incoming) return;
auto callCore = CallCore::create(call);
mCoreModelConnection->invokeToCore([this, callCore] {
@ -367,7 +386,7 @@ void App::setSelf(QSharedPointer<App>(me)) {
mCoreModelConnection->makeConnectToModel(&CoreModel::requestRestart, [this]() {
mCoreModelConnection->invokeToCore([this]() {
lInfo() << log().arg("Restarting");
restart();
restartCore();
});
});
mCoreModelConnection->makeConnectToModel(&CoreModel::requestFetchConfig, [this](QString path,
@ -404,6 +423,7 @@ void App::setSelf(QSharedPointer<App>(me)) {
&CoreModel::globalStateChanged,
[this](const std::shared_ptr<linphone::Core> &core, linphone::GlobalState gstate, const std::string &message) {
mCoreModelConnection->invokeToCore([this, gstate] {
lInfo() << log().arg("Core global state changed :") << (int)gstate;
setCoreStarted(gstate == linphone::GlobalState::On);
if (gstate == linphone::GlobalState::Configuring) {
if (mMainWindow) {
@ -578,9 +598,9 @@ void App::setSelf(QSharedPointer<App>(me)) {
connect(&mOIDCRefreshTimer, &QTimer::timeout, this, [this]() {
mCoreModelConnection->invokeToModel([this] { CoreModel::getInstance()->refreshOidcRemainingTime(); });
});
}
//---------------------------------------------------------------------------------------------
mCliModelConnection = SafeConnection<App, CliModel>::create(me, CliModel::getInstance());
void App::connectCliModel() {
mCliModelConnection->makeConnectToCore(&App::receivedMessage, [this](int, const QByteArray &byteArray) {
QString command(byteArray);
if (command.isEmpty()) {
@ -596,6 +616,14 @@ void App::setSelf(QSharedPointer<App>(me)) {
});
}
void App::setSelf(QSharedPointer<App>(me)) {
mCoreModelConnection = SafeConnection<App, CoreModel>::create(me, CoreModel::getInstance());
connectCoreModel();
//---------------------------------------------------------------------------------------------
mCliModelConnection = SafeConnection<App, CliModel>::create(me, CliModel::getInstance());
connectCliModel();
}
App *App::getInstance() {
return dynamic_cast<App *>(QApplication::instance());
}
@ -675,10 +703,12 @@ void App::initCore() {
lInfo() << log().arg("Starting Core");
CoreModel::getInstance()->start();
ToolModel::loadDownloadedCodecs();
lDebug() << log().arg("Creating SettingsModel");
SettingsModel::create();
lDebug() << log().arg("Creating SettingsCore");
settings = SettingsCore::create();
if (!settings) {
lDebug() << log().arg("Creating SettingsModel");
SettingsModel::create();
lDebug() << log().arg("Creating SettingsCore");
settings = SettingsCore::create();
}
// Update the download folder if set in the configuration file
CoreModel::getInstance()->setPathsAfterCreation();
lDebug() << log().arg("Checking downloaded codecs updates");
@ -701,8 +731,11 @@ void App::initCore() {
lWarning() << "[Main] The application doesn't support the CrashReporter.";
#endif
// QML
mEngine = new QQmlApplicationEngine(this);
assert(mEngine);
if (!mEngine) {
mEngine = new QQmlApplicationEngine(this);
assert(mEngine);
}
mSettings = settings;
// Provide `+custom` folders for custom components and `5.9` for old components.
QStringList selectors("custom");
const QVersionNumber &version = QLibraryInfo::version();
@ -715,22 +748,22 @@ void App::initCore() {
#ifdef APPLICATION_VENDOR
mEngine->rootContext()->setContextProperty("applicationVendor", APPLICATION_VENDOR);
#else
mEngine->rootContext()->setContextProperty("applicationVendor", "");
mEngine->rootContext()->setContextProperty("applicationVendor", "");
#endif
#ifdef APPLICATION_LICENCE
mEngine->rootContext()->setContextProperty("applicationLicence", APPLICATION_LICENCE);
#else
mEngine->rootContext()->setContextProperty("applicationLicence", "");
mEngine->rootContext()->setContextProperty("applicationLicence", "");
#endif
#ifdef APPLICATION_LICENCE_URL
mEngine->rootContext()->setContextProperty("applicationLicenceUrl", APPLICATION_LICENCE_URL);
#else
mEngine->rootContext()->setContextProperty("applicationLicenceUrl", "");
mEngine->rootContext()->setContextProperty("applicationLicenceUrl", "");
#endif
#ifdef COPYRIGHT_RANGE_DATE
mEngine->rootContext()->setContextProperty("copyrightRangeDate", COPYRIGHT_RANGE_DATE);
#else
mEngine->rootContext()->setContextProperty("copyrightRangeDate", "");
mEngine->rootContext()->setContextProperty("copyrightRangeDate", "");
#endif
mEngine->rootContext()->setContextProperty("applicationName", APPLICATION_NAME);
mEngine->rootContext()->setContextProperty("executableName", EXECUTABLE_NAME);
@ -746,12 +779,12 @@ void App::initCore() {
mEngine->addImageProvider(ThumbnailProvider::ProviderId, new ThumbnailProvider());
// Enable notifications.
mNotifier = new Notifier(mEngine);
if (!mNotifier) mNotifier = new Notifier(mEngine);
mEngine->setObjectOwnership(settings.get(), QQmlEngine::CppOwnership);
mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
mNotificationBackend = new NotificationBackend(this);
if (!mNotificationBackend) mNotificationBackend = new NotificationBackend(this);
#endif
auto initLists = [this] {
@ -790,7 +823,6 @@ void App::initCore() {
} else connect(this, &App::coreStartedChanged, this, initLists);
// if (!mSettings) {
mSettings = settings;
setLocale(settings->getConfigLocale());
setAutoStart(settings->getAutoStart());
setQuitOnLastWindowClosed(settings->getExitOnClose());
@ -814,81 +846,85 @@ void App::initCore() {
// setQuitOnLastWindowClosed(settings->getExitOnClose());
// }
const QUrl url("qrc:/qt/qml/Linphone/view/Page/Window/Main/MainWindow.qml");
QObject::connect(
mEngine, &QQmlApplicationEngine::objectCreated, this,
[this, url](QObject *obj, const QUrl &objUrl) {
if (url == objUrl) {
if (!obj) {
lCritical() << log().arg("MainWindow.qml couldn't be load. The app will exit");
exit(-1);
}
auto window = qobject_cast<QQuickWindow *>(obj);
setMainWindow(window);
if (!mMainWindow) {
QObject::connect(
mEngine, &QQmlApplicationEngine::objectCreated, this,
[this, url](QObject *obj, const QUrl &objUrl) {
if (url == objUrl) {
if (!obj) {
lCritical() << log().arg("MainWindow.qml couldn't be load. The app will exit");
exit(-1);
}
auto window = qobject_cast<QQuickWindow *>(obj);
setMainWindow(window);
#if defined(__APPLE__)
setMacOSDockActions();
setMacOSDockActions();
#else
// Enable TrayIconSystem.
if (!QSystemTrayIcon::isSystemTrayAvailable())
qWarning("System tray not found on this system.");
else setSysTrayIcon();
// Enable TrayIconSystem.
if (!QSystemTrayIcon::isSystemTrayAvailable())
qWarning("System tray not found on this system.");
else setSysTrayIcon();
#endif // if defined(__APPLE__)
static bool firstOpen = true;
if (!firstOpen || !mParser->isSet("minimized")) {
lDebug() << log().arg("Openning window");
if (window) window->show();
} else lInfo() << log().arg("Stay minimized");
firstOpen = false;
lInfo() << log().arg("Checking remote provisioning");
if (mIsRestarting) {
auto handleConfigStatus = [this] {
if (CoreModel::getInstance()->mConfigStatus == linphone::ConfiguringState::Failed) {
QMetaObject::invokeMethod(thread(), [this]() {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
auto message = CoreModel::getInstance()->mConfigMessage;
//: not reachable
if (message.isEmpty()) message = tr("configuration_error_detail");
lWarning() << log().arg("Configuration failed (reason: %1)").arg(message);
//: Error
Utils::showInformationPopup(
tr("info_popup_error_title"),
//: Remote provisioning failed : %1
tr("info_popup_configuration_failed_message").arg(message), false);
});
} else if (CoreModel::getInstance()->mConfigStatus ==
linphone::ConfiguringState::Successful) {
lInfo() << log().arg("Configuration succeed");
mPossiblyLookForAddedAccount = true;
if (mAccountList && mAccountList->getCount() > 0) {
auto defaultConnected =
mAccountList->getDefaultAccountCore() &&
mAccountList->getDefaultAccountCore()->getRegistrationState() ==
LinphoneEnums::RegistrationState::Ok;
QMetaObject::invokeMethod(mMainWindow, "openMainPage", Qt::DirectConnection,
Q_ARG(QVariant, defaultConnected));
static bool firstOpen = true;
if (!firstOpen || !mParser->isSet("minimized")) {
lDebug() << log().arg("Openning window");
if (window) window->show();
} else lInfo() << log().arg("Stay minimized");
firstOpen = false;
lInfo() << log().arg("Checking remote provisioning");
if (mIsRestarting) {
auto handleConfigStatus = [this] {
if (CoreModel::getInstance()->mConfigStatus ==
linphone::ConfiguringState::Failed) {
QMetaObject::invokeMethod(thread(), [this]() {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
auto message = CoreModel::getInstance()->mConfigMessage;
//: not reachable
if (message.isEmpty()) message = tr("configuration_error_detail");
lWarning()
<< log().arg("Configuration failed (reason: %1)").arg(message);
//: Error
Utils::showInformationPopup(
tr("info_popup_error_title"),
//: Remote provisioning failed : %1
tr("info_popup_configuration_failed_message").arg(message), false);
});
} else if (CoreModel::getInstance()->mConfigStatus ==
linphone::ConfiguringState::Successful) {
lInfo() << log().arg("Configuration succeed");
mPossiblyLookForAddedAccount = true;
if (mAccountList && mAccountList->getCount() > 0) {
auto defaultConnected =
mAccountList->getDefaultAccountCore() &&
mAccountList->getDefaultAccountCore()->getRegistrationState() ==
LinphoneEnums::RegistrationState::Ok;
QMetaObject::invokeMethod(mMainWindow, "openMainPage",
Qt::DirectConnection,
Q_ARG(QVariant, defaultConnected));
}
}
};
if (mMainWindow) {
handleConfigStatus();
} else {
connect(this, &App::mainWindowChanged, this, handleConfigStatus,
Qt::SingleShotConnection);
}
};
if (mMainWindow) {
handleConfigStatus();
} else {
connect(this, &App::mainWindowChanged, this, handleConfigStatus,
Qt::SingleShotConnection);
}
if (mSettings->autoCheckForUpdateOnStart()) checkForUpdate();
window->show();
window->requestActivate();
//---------------------------------------------------------------------------------------------
lDebug() << log().arg("Creating KeyboardShortcuts");
KeyboardShortcuts::create(getMainWindow());
}
if (mSettings->autoCheckForUpdateOnStart()) checkForUpdate();
setIsRestarting(false);
window->show();
window->requestActivate();
},
Qt::QueuedConnection);
//---------------------------------------------------------------------------------------------
lDebug() << log().arg("Creating KeyboardShortcuts");
KeyboardShortcuts::create(getMainWindow());
}
},
Qt::QueuedConnection);
mEngine->load(url);
mEngine->load(url);
}
});
},
Qt::BlockingQueuedConnection);
@ -1115,33 +1151,28 @@ void App::clean() {
delete mLinphoneThread;
}
}
void App::restart() {
void App::restartCore() {
setIsRestarting(true);
mCoreModelConnection->invokeToModel([this]() {
FriendsManager::getInstance()->clearMaps();
CoreModel::getInstance()->getCore()->stop();
mCoreModelConnection->invokeToCore([this]() {
setIsRestarting(true);
mCoreModelConnection->invokeToCore([this] {
if (mAccountList) mAccountList->resetData();
if (mCallList) mCallList->resetData();
if (mCallHistoryList) mCallHistoryList->resetData();
if (mChatList) mChatList->resetData();
if (mConferenceInfoList) mConferenceInfoList->resetData();
closeCallsWindow();
setMainWindow(nullptr);
// setMainWindow(nullptr);
setCoreStarted(false);
mEngine->clearComponentCache();
mEngine->clearSingletons();
delete mEngine;
mEngine = nullptr;
// if (mSettings) mSettings.reset();
initCore();
// Retrieve self from current Core/Model connection and reset Qt connections.
// auto oldConnection = mCoreModelConnection;
// oldConnection->mCore.lock();
// auto me = oldConnection->mCore.mQData;
// setSelf(me);
// oldConnection->mCore.unlock();
exit((int)StatusCode::gRestartCode);
// delete mEngine;
// mEngine = nullptr;
// clean();
// mLinphoneThread = new Thread(this);
// mCoreModelConnection->disconnect();
emit restartCoreRequested();
});
});
}
@ -1186,10 +1217,10 @@ void App::createCommandParser() {
});
}
// Should be call only at first start
void App::sendCommand() {
void App::sendCommand(bool firstStart) {
auto arguments = mParser->positionalArguments();
if (mParser->isSet("fetch-config")) arguments << "fetch-config=" + mParser->value("fetch-config");
static bool firstStart = true; // We can't erase positional arguments. So we get them on each restart.
// static bool firstStart = true; // We can't erase positional arguments. So we get them on each restart.
if (firstStart) {
firstStart = false;
if (isSecondary()) { // Send to primary

View file

@ -66,6 +66,9 @@ public:
App(int &argc, char *argv[]);
~App();
void setSelf(QSharedPointer<App>(me));
void resetConnections();
void connectCoreModel();
void connectCliModel();
static App *getInstance();
static Thread *getLinphoneThread();
Notifier *getNotifier() const;
@ -135,7 +138,7 @@ public:
void initLocale();
void initCppInterfaces();
void initFonts();
void restart();
void restartCore();
bool autoStartEnabled();
void setSysTrayIcon();
QSystemTrayIcon *getSystemTrayIcon() const {
@ -146,7 +149,7 @@ public:
QString getLocaleAsString();
void onLoggerInitialized();
void sendCommand();
void sendCommand(bool firstStart = true);
bool getCoreStarted() const;
void setCoreStarted(bool started);
@ -242,6 +245,7 @@ signals:
void lForceOidcTimeout();
void remainingTimeBeforeOidcTimeoutChanged();
void currentAccountChanged();
void restartCoreRequested();
#ifdef Q_OS_WIN
void sessionLockedChanged();
#endif

View file

@ -57,7 +57,7 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
mModelConnection = SafeConnection<CallHistoryList, CoreModel>::create(me, CoreModel::getInstance());
mModelConnection->makeConnectToCore(&CallHistoryList::lUpdate, [this](bool signalReset) {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
mustBeInMainThread(log().arg(Q_FUNC_INFO) + "lUpdate");
if (signalReset) emit listAboutToBeReset();
mModelConnection->invokeToModel([this]() {
mustBeInLinphoneThread(Q_FUNC_INFO);
@ -73,7 +73,7 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
callLogs->push_front(model);
}
mModelConnection->invokeToCore([this, callLogs]() {
mustBeInMainThread(Q_FUNC_INFO);
mustBeInMainThread(log().arg(Q_FUNC_INFO));
beginResetModel();
mList.clear();
for (auto &item : *callLogs) {
@ -94,10 +94,11 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
lInfo() << "call log does not refer to current account, return";
return;
}
emit lUpdate(false);
mModelConnection->invokeToCore([this]() { lUpdate(false); });
// auto callLogCore = createCallHistoryCore(callLog);
// mModelConnection->invokeToCore([this, callLogCore]() {
// auto oldLog = std::find_if(mList.begin(), mList.end(), [callLogCore](QSharedPointer<QObject> log) {
// auto oldLog = std::find_if(mList.begin(), mList.end(), [callLogCore](QSharedPointer<QObject> log)
// {
// return (callLogCore)->mCallId == log.objectCast<CallHistoryCore>()->mCallId;
// });
// toConnect(callLogCore.get());

View file

@ -286,7 +286,7 @@ OIDCModel::OIDCModel(const std::shared_ptr<linphone::AuthInfo> &authInfo, QObjec
}
void OIDCModel::forceTimeout() {
lWarning() << log().arg("Froce timeout for OpenID connection.");
lInfo() << log().arg("Froce timeout for OpenID connection.");
stopTimeoutTimer();
dynamic_cast<OAuthHttpServerReplyHandler *>(mOidc.replyHandler())->close();
CoreModel::getInstance()->getCore()->abortAuthentication(mAuthInfo);
@ -311,7 +311,7 @@ void OIDCModel::stopTimeoutTimer() {
void OIDCModel::openIdConfigReceived() {
auto reply = dynamic_cast<QNetworkReply *>(sender());
auto replyArray = reply->readAll();
lInfo() << log().arg("Reply :") << replyArray;
lDebug() << log().arg("Reply :") << replyArray;
auto document = QJsonDocument::fromJson(replyArray);
if (document.isNull()) {
lWarning() << log().arg("Reply is empty");

View file

@ -445,6 +445,7 @@ void CoreModel::onAuthenticationRequested(const std::shared_ptr<linphone::Core>
}
connect(oidcModel, &OIDCModel::timeoutTimerStopped, this, [this] { emit timeoutTimerStopped(); });
connect(this, &CoreModel::forceOidcTimeout, oidcModel, [this, oidcModel] {
lDebug() << log().arg("Force OIDC timeout");
if (oidcModel->isTimerRunning()) {
oidcModel->forceTimeout();
}

View file

@ -105,6 +105,10 @@ public:
me->setSelf(me);
return me;
}
void setModel(std::shared_ptr<B> model) {
mModel = model;
mModelObject = model.get();
}
SafeSharedPointer<A> mCore;
SafeSharedPointer<B> mModel;

View file

@ -57,7 +57,8 @@ public:
}
}
void unlock() {
if (mCountRef == 0) qWarning() << "[SafeConnection] too much unlocking";
if (mCountRef == 0)
qWarning() << "[SafeConnection] too much unlocking on " << QString(typeid(A).name()) << "pointer";
else if (--mCountRef == 0) {
mQData = nullptr;
mStdData = nullptr;