- Unregister account prior removal (set expires to 0 to prevent receiving calls after account is removed)

- Request user confirmation to force remove an account even if unable to unregister
This commit is contained in:
Christophe Deschamps 2024-10-17 06:39:53 +02:00
parent 7c70c9b85d
commit 8f09769f87
7 changed files with 103 additions and 25 deletions

View file

@ -3410,6 +3410,10 @@ Click here: <a href="%1">%1</a>
<source>deleteAccountDescription</source>
<translation>Are you sure you wish to delete this account?</translation>
</message>
<message>
<source>deleteAccountDescriptionUnregisterFailed</source>
<translation>Unable to unregister this account from server. Do you wish to delete it anyway?</translation>
</message>
<message>
<source>eraseAllPasswordsDescription</source>
<translation>Are you sure you wish to remove all passwords?</translation>

View file

@ -3385,6 +3385,10 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<source>deleteAccountDescription</source>
<translation>Êtes-vous sûr de vouloir supprimer ce compte ?</translation>
</message>
<message>
<source>deleteAccountDescriptionUnregisterFailed</source>
<translation>Le désenregistrement de ce compte auprès du serveur a échoué. Le supprimer quand même ?</translation>
</message>
<message>
<source>eraseAllPasswordsDescription</source>
<translation>Êtes-vous sûr de vouloir supprimer tous vos mots de passe ?</translation>

View file

@ -298,7 +298,7 @@ void AccountSettingsModel::enableRegister (std::shared_ptr<linphone::Account> ac
account->setParams(params);
}
void AccountSettingsModel::removeAccount (const shared_ptr<linphone::Account> &account) {
void AccountSettingsModel::removeAccount (const shared_ptr<linphone::Account> &account, bool unregisterFirst) {
CoreManager *coreManager = CoreManager::getInstance();
std::shared_ptr<linphone::Account> newAccount = nullptr;
@ -312,6 +312,16 @@ void AccountSettingsModel::removeAccount (const shared_ptr<linphone::Account> &a
}
setDefaultAccount(newAccount);
}
if (!unregisterFirst || !account->getParams()->registerEnabled()) {
doRemoveAccount(account);
return;
}
if (account->getState() == linphone::RegistrationState::None) {
emit unregisterFailed();
return;
}
// "message-expires" is used to keep contact for messages. Setting to 0 will remove the contact for messages too.
// Check if a "message-expires" exists and set it to 0
QStringList parameters = Utils::coreStringToAppString(account->getParams()->getContactParameters()).split(";", Qt::SkipEmptyParts);
@ -321,16 +331,26 @@ void AccountSettingsModel::removeAccount (const shared_ptr<linphone::Account> &a
parameters[i] = Constants::DefaultContactParametersOnRemove;
}
}
auto accountParams = account->getParams()->clone();
accountParams->setContactParameters(Utils::appStringToCoreString(parameters.join(";")));
accountParams->setContactParameters(Utils::appStringToCoreString(parameters.join(";")));
accountParams->setExpires(0);
bool isRegistered = account->getState() == linphone::RegistrationState::Ok;
if (account->setParams(accountParams) == -1) {
qWarning() << QStringLiteral("Unable to reset message-expiry property before removing account: `%1`.")
.arg(QString::fromStdString(account->getParams()->getIdentityAddress()->asString()));
}else if(isRegistered && account->getParams()->registerEnabled()) { // Wait for update
}else if (isRegistered) { // Wait for unregistration
mRemovingAccounts.push_back(account);
QTimer::singleShot(10000, [account, this](){// In case of unregistration failure.
if (!mRemovedAccounts.contains(account)) {
mRemovingAccounts.removeAll(account);
qInfo() << QStringLiteral("failed unregistering from server within 10 seconds, deleting account %1.").arg(Utils::coreStringToAppString(account->getParams()->getIdentityAddress()->asString()));
emit unregisterFailed();
} else
mRemovedAccounts.removeAll(account);
});
}else{// Registration is not enabled : Removing without wait.
CoreManager::getInstance()->getCore()->removeAccount(account);
doRemoveAccount(account);
}
emit accountSettingsUpdated();
@ -644,23 +664,27 @@ void AccountSettingsModel::handleRegistrationStateChanged (
const shared_ptr<linphone::Account> & account,
linphone::RegistrationState state
) {
Q_UNUSED(state)
auto coreManager = CoreManager::getInstance();
shared_ptr<linphone::Account> defaultAccount = coreManager->getCore()->getDefaultAccount();
if( state == linphone::RegistrationState::Cleared){
auto authInfo = account->findAuthInfo();
if(authInfo)
QTimer::singleShot(60000, [authInfo](){// 60s is just to be sure. account_update remove deleted account only after 32s
CoreManager::getInstance()->getCore()->removeAuthInfo(authInfo);
});
}else if(mRemovingAccounts.contains(account)){
if(mRemovingAccounts.contains(account) && state == linphone::RegistrationState::Cleared) {
mRemovingAccounts.removeAll(account);
QTimer::singleShot(100, [account, this](){// removeAccount cannot be called from callback
CoreManager::getInstance()->getCore()->removeAccount(account);
emit accountsChanged();
});
doRemoveAccount(account);
}
if(defaultAccount == account)
emit defaultRegistrationChanged();
emit registrationStateChanged();
}
void AccountSettingsModel::doRemoveAccount (const shared_ptr<linphone::Account> &account) {
auto authInfo = account->findAuthInfo();
if(authInfo)
QTimer::singleShot(60000, [authInfo](){// 60s is just to be sure. account_update remove deleted account only after 32s
CoreManager::getInstance()->getCore()->removeAuthInfo(authInfo);
});
QTimer::singleShot(100, [account, this](){// removeAccount cannot be called from callback
CoreManager::getInstance()->getCore()->removeAccount(account);
emit accountsChanged();
});
}

View file

@ -95,7 +95,7 @@ public:
Q_INVOKABLE bool addOrUpdateAccount (const std::shared_ptr<linphone::Account> &account, const QVariantMap &data);
Q_INVOKABLE bool addOrUpdateAccount (const QVariantMap &data);// Create default account and apply data
Q_INVOKABLE void removeAccount (const std::shared_ptr<linphone::Account> &account);
Q_INVOKABLE void removeAccount (const std::shared_ptr<linphone::Account> &account, bool unregisterFirst);
Q_INVOKABLE std::shared_ptr<linphone::Account> createAccount (const QString& assistantFile);
@ -122,7 +122,8 @@ signals:
void primarySipAddressChanged();
void accountsChanged();
void unregisterFailed();
void accountSettingsUpdated ();
void defaultAccountChanged();
void publishPresenceChanged();
@ -151,13 +152,15 @@ private:
QVariantList getAccounts () const;
// ---------------------------------------------------------------------------
void handleRegistrationStateChanged (
const std::shared_ptr<linphone::Account> &account,
linphone::RegistrationState state
);
void doRemoveAccount (const std::shared_ptr<linphone::Account> &account);
QVector<std::shared_ptr<linphone::Account> > mRemovingAccounts;
QVector<std::shared_ptr<linphone::Account> > mRemovedAccounts;
std::shared_ptr<linphone::Account> mSelectedAccount;
};

View file

@ -33,16 +33,29 @@ function editAccount (account) {
})
}
function deleteAccount (account) {
function confirmDeleteAccount (account, confirmedLambda) {
window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), {
descriptionText: qsTr('deleteAccountDescription'),
}, function (status) {
if (status) {
Linphone.AccountSettingsModel.removeAccount(account.account)
confirmedLambda()
Linphone.AccountSettingsModel.removeAccount(account.account, true)
}
})
}
function confirmDeleteAccountUnregisterFailed (account, cancelLambda) {
window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), {
descriptionText: qsTr('deleteAccountDescriptionUnregisterFailed'),
}, function (status) {
if (status) {
Linphone.AccountSettingsModel.removeAccount(account.account, false)
} else {
cancelLambda()
}
})
}
function eraseAllPasswords () {
window.attachVirtualWindow(Utils.buildCommonDialogUri('ConfirmDialog'), {
descriptionText: qsTr('eraseAllPasswordsDescription'),

View file

@ -4,8 +4,10 @@ import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import UtilsCpp 1.0
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
import App.Styles 1.0
import Common.Styles 1.0
import 'SettingsSipAccounts.js' as Logic
@ -101,18 +103,42 @@ TabContainer {
isCustom: true
backgroundRadius: 4
colorSet: SettingsWindowStyle.buttons.editProxy
enabled: !deleteButton.deleteInProgress
onClicked: Logic.editAccount(modelData)
}
}
FormTableEntry {
ActionButton {
id: deleteButton
isCustom: true
backgroundRadius: 4
colorSet: SettingsWindowStyle.buttons.deleteProxy
onClicked: Logic.deleteAccount(modelData)
property bool deleteInProgress: false
enabled: !deleteInProgress
onClicked: {
Logic.confirmDeleteAccount(modelData, function() {
deleteInProgress = true
})
}
Connections {
target: AccountSettingsModel
enabled: deleteButton.deleteInProgress
onUnregisterFailed: {
Logic.confirmDeleteAccountUnregisterFailed(modelData, function() {
deleteButton.deleteInProgress = false
})
}
}
BusyIndicator {
anchors {
horizontalCenter: parent.horizontalCenter
fill: parent
}
color: BusyIndicatorStyle.alternateColor.color
running: true
visible: deleteButton.deleteInProgress
}
}
}
}

View file

@ -37,9 +37,11 @@ QtObject {
property string name : 'editProxy'
property string icon : 'edit_custom'
property var backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg')
property var backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_d_b_bg')
property var backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg')
property var backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg')
property var foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg')
property var foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_d_b_fg')
property var foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg')
property var foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg')
}
@ -48,9 +50,11 @@ QtObject {
property string name : 'deleteProxy'
property string icon : 'delete_custom'
property var backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg')
property var backgroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_d_b_bg')
property var backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg')
property var backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_p', icon, 'me_p_b_bg')
property var foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_n_b_fg')
property var foregroundDisabledColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_n', icon, 'me_d_b_fg')
property var foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_fg')
property var foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_fg')
}