login with non linphone sip account

This commit is contained in:
Gaelle Braud 2024-08-21 13:56:40 +02:00
parent 5adf150d2d
commit 4ec344130d
15 changed files with 105 additions and 110 deletions

View file

@ -52,7 +52,10 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
mRegisterEnabled = params->registerEnabled();
mMwiServerAddress =
params->getMwiServerAddress() ? Utils::coreStringToAppString(params->getMwiServerAddress()->asString()) : "";
mTransports << "TCP" << "UDP" << "TLS" << "DTLS";
mTransports << "TCP"
<< "UDP"
<< "TLS"
<< "DTLS";
mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(params->getTransport()));
mServerAddress =
params->getServerAddress() ? Utils::coreStringToAppString(params->getServerAddress()->asString()) : "";
@ -98,76 +101,76 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
&AccountModel::registrationStateChanged, [this](const std::shared_ptr<linphone::Account> &account,
linphone::RegistrationState state, const std::string &message) {
mAccountModelConnection->invokeToCore(
[this, account, state, message]() { this->onRegistrationStateChanged(account, state, message); });
[this, account, state, message]() { onRegistrationStateChanged(account, state, message); });
});
// From Model
mAccountModelConnection->makeConnectToModel(&AccountModel::defaultAccountChanged, [this](bool isDefault) {
mAccountModelConnection->invokeToCore([this, isDefault]() { this->onDefaultAccountChanged(isDefault); });
mAccountModelConnection->invokeToCore([this, isDefault]() { onDefaultAccountChanged(isDefault); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::pictureUriChanged, [this](QString uri) {
mAccountModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); });
mAccountModelConnection->invokeToCore([this, uri]() { onPictureUriChanged(uri); });
});
mAccountModelConnection->makeConnectToModel(
&AccountModel::unreadNotificationsChanged, [this](int unreadMessagesCount, int unreadCallsCount) {
mAccountModelConnection->invokeToCore([this, unreadMessagesCount, unreadCallsCount]() {
this->setUnreadNotifications(unreadMessagesCount + unreadCallsCount);
this->setUnreadCallNotifications(unreadCallsCount);
this->setUnreadMessageNotifications(unreadMessagesCount);
setUnreadNotifications(unreadMessagesCount + unreadCallsCount);
setUnreadCallNotifications(unreadCallsCount);
setUnreadMessageNotifications(unreadMessagesCount);
});
});
mAccountModelConnection->makeConnectToModel(&AccountModel::displayNameChanged, [this](QString displayName) {
mAccountModelConnection->invokeToCore([this, displayName]() { this->onDisplayNameChanged(displayName); });
mAccountModelConnection->invokeToCore([this, displayName]() { onDisplayNameChanged(displayName); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::dialPlanChanged, [this](int index) {
auto dialPlan = mDialPlans[index + 1];
mAccountModelConnection->invokeToCore([this, dialPlan]() { this->onDialPlanChanged(dialPlan); });
mAccountModelConnection->invokeToCore([this, dialPlan]() { onDialPlanChanged(dialPlan); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::registerEnabledChanged, [this](bool enabled) {
mAccountModelConnection->invokeToCore([this, enabled]() { this->onRegisterEnabledChanged(enabled); });
mAccountModelConnection->invokeToCore([this, enabled]() { onRegisterEnabledChanged(enabled); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::notificationsAllowedChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onNotificationsAllowedChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onNotificationsAllowedChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::mwiServerAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onMwiServerAddressChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onMwiServerAddressChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::transportChanged, [this](linphone::TransportType value) {
mAccountModelConnection->invokeToCore(
[this, value]() { this->onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(value))); });
[this, value]() { onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(value))); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::serverAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onServerAddressChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onServerAddressChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::outboundProxyEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onOutboundProxyEnabledChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onOutboundProxyEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::stunServerChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onStunServerChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onStunServerChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::iceEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onIceEnabledChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onIceEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::avpfEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onAvpfEnabledChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onAvpfEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::bundleModeEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onBundleModeEnabledChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onBundleModeEnabledChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::expireChanged, [this](int value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onExpireChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onExpireChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::conferenceFactoryAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onConferenceFactoryAddressChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onConferenceFactoryAddressChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::audioVideoConferenceFactoryAddressChanged,
[this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() {
this->onAudioVideoConferenceFactoryAddressChanged(value);
onAudioVideoConferenceFactoryAddressChanged(value);
});
});
mAccountModelConnection->makeConnectToModel(&AccountModel::limeServerUrlChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { this->onLimeServerUrlChanged(value); });
mAccountModelConnection->invokeToCore([this, value]() { onLimeServerUrlChanged(value); });
});
// From GUI
@ -252,6 +255,10 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
});
}
const std::shared_ptr<AccountModel> &AccountCore::getModel() const {
return mAccountModel;
}
QString AccountCore::getContactAddress() const {
return mContactAddress;
}

View file

@ -79,9 +79,12 @@ public:
~AccountCore();
void setSelf(QSharedPointer<AccountCore> me);
const std::shared_ptr<AccountModel> &getModel() const;
QString getContactAddress() const;
QString getIdentityAddress() const;
QString getPictureUri() const;
void onPictureUriChanged(QString uri);
LinphoneEnums::RegistrationState getRegistrationState() const;
bool getIsDefaultAccount() const;
int getUnreadNotifications() const;
@ -91,7 +94,6 @@ public:
int getUnreadMessageNotifications() const;
void setUnreadMessageNotifications(int unread);
void onPictureUriChanged(QString uri);
void onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account,
linphone::RegistrationState state,
const std::string &message);

View file

@ -38,8 +38,6 @@ QSharedPointer<AccountList> AccountList::create() {
AccountList::AccountList(QObject *parent) : ListProxy(parent) {
mustBeInMainThread(getClassName());
connect(CoreModel::getInstance().get(), &CoreModel::accountAdded, this, &AccountList::lUpdate);
connect(CoreModel::getInstance().get(), &CoreModel::accountRemoved, this, &AccountList::lUpdate);
}
AccountList::~AccountList() {
@ -82,6 +80,9 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
mModelConnection->invokeToCore([this, model]() { setDefaultAccount(model); });
} else mModelConnection->invokeToCore([this]() { setDefaultAccount(nullptr); });
});
mModelConnection->makeConnectToModel(&CoreModel::accountRemoved, &AccountList::lUpdate);
mModelConnection->makeConnectToModel(&CoreModel::accountAdded, &AccountList::lUpdate);
lUpdate();
}

View file

@ -55,8 +55,10 @@ QString LoginPage::getErrorMessage() const {
void LoginPage::setErrorMessage(const QString &error) {
// force signal emission to display the error even if it doesn't change
mErrorMessage = error;
emit errorMessageChanged();
if (mErrorMessage != error) {
mErrorMessage = error;
emit errorMessageChanged(error);
}
}
void LoginPage::login(const QString &username,
@ -65,16 +67,15 @@ void LoginPage::login(const QString &username,
QString domain,
LinphoneEnums::TransportType transportType) {
App::postModelAsync([=]() {
QString *error = new QString(tr("Le couple identifiant mot de passe ne correspond pas"));
// Create on Model thread.
AccountManager *accountManager = new AccountManager();
connect(accountManager, &AccountManager::registrationStateChanged, this,
[accountManager, this, error](linphone::RegistrationState state) mutable {
[accountManager, this](linphone::RegistrationState state) mutable {
// View thread
setRegistrationState(state);
switch (state) {
case linphone::RegistrationState::Failed: {
emit accountManager->errorMessageChanged(*error);
setErrorMessage(QString(tr("Le couple identifiant mot de passe ne correspond pas")));
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
@ -82,7 +83,7 @@ void LoginPage::login(const QString &username,
break;
}
case linphone::RegistrationState::Ok: {
emit accountManager->errorMessageChanged("");
// setErrorMessage("");
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
@ -102,14 +103,12 @@ void LoginPage::login(const QString &username,
break;
}
});
connect(accountManager, &AccountManager::errorMessageChanged, this,
[this](QString errorMessage) { setErrorMessage(errorMessage); });
connect(accountManager, &AccountManager::destroyed, [error]() { delete error; });
QString error;
if (!accountManager->login(username, password, displayName, domain, LinphoneEnums::toLinphone(transportType),
error)) {
emit accountManager->registrationStateChanged(linphone::RegistrationState::Failed);
&error)) {
setErrorMessage(error);
emit accountManager->registrationStateChanged(linphone::RegistrationState::None);
}
});
}

View file

@ -40,7 +40,7 @@ public:
const QString &password,
QString displayName = QString(),
QString domain = QString(),
LinphoneEnums::TransportType transportType = LinphoneEnums::TransportType::Tcp);
LinphoneEnums::TransportType transportType = LinphoneEnums::TransportType::Tls);
linphone::RegistrationState getRegistrationState() const;
void setRegistrationState(linphone::RegistrationState status);
@ -50,7 +50,7 @@ public:
signals:
void registrationStateChanged();
void errorMessageChanged();
void errorMessageChanged(QString error);
private:
linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None;
@ -59,4 +59,4 @@ private:
DECLARE_ABSTRACT_OBJECT
};
#endif
#endif

View file

@ -63,7 +63,10 @@ bool AccountManager::login(QString username,
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
auto factory = linphone::Factory::get();
auto account = createAccount("use-app-sip-account.rc");
QString assistantFile = (!QString::compare(domain, "sip.linphone.org") || domain.isEmpty())
? "use-app-sip-account.rc"
: "use-other-sip-account.rc";
auto account = createAccount(assistantFile);
auto params = account->getParams()->clone();
// Sip address.
auto identity = params->getIdentityAddress()->clone();
@ -80,8 +83,20 @@ bool AccountManager::login(QString username,
username = Utils::getUsername(username);
identity->setUsername(Utils::appStringToCoreString(username));
if (!displayName.isEmpty()) identity->setDisplayName(Utils::appStringToCoreString(displayName));
identity->setTransport(transportType);
if (!domain.isEmpty()) identity->setDomain(Utils::appStringToCoreString(domain));
if (!domain.isEmpty()) {
identity->setDomain(Utils::appStringToCoreString(domain));
if (!domain.isEmpty() && QString::compare(domain, "sip.linphone.org")) {
params->setLimeServerUrl("");
auto serverAddress =
factory->createAddress(Utils::appStringToCoreString(QStringLiteral("sip:%1").arg(domain)));
if (!serverAddress) {
*errorMessage = tr("Impossible de créer l'adresse proxy. Merci de vérifier le nom de domaine.");
return false;
}
serverAddress->setTransport(transportType);
params->setServerAddress(serverAddress);
}
}
if (params->setIdentityAddress(identity)) {
qWarning() << log()
.arg(QStringLiteral("Unable to set identity address: `%1`."))
@ -91,7 +106,10 @@ bool AccountManager::login(QString username,
return false;
}
account->setParams(params);
if (account->setParams(params)) {
*errorMessage = tr("Impossible de configurer les paramètres du compte.");
return false;
}
core->addAuthInfo(factory->createAuthInfo(Utils::appStringToCoreString(username), // Username.
"", // User ID.
Utils::appStringToCoreString(password), // Password.
@ -103,7 +121,11 @@ bool AccountManager::login(QString username,
mAccountModel->setSelf(mAccountModel);
connect(mAccountModel.get(), &AccountModel::registrationStateChanged, this,
&AccountManager::onRegistrationStateChanged);
core->addAccount(account);
auto status = core->addAccount(account);
if (status == -1) {
*errorMessage = tr("Impossible d'ajouter le compte.");
return false;
}
return true;
}
@ -155,7 +177,7 @@ void AccountManager::registerNewAccount(const QString &username,
"", // User ID.
Utils::appStringToCoreString(password), // Password.
"", // HA1.
"", // Realm.
createdSipIdentityAddress->getDomain(), // Realm.
createdSipIdentityAddress->getDomain() // Domain.
));
if (type == RegisterType::Email) {

View file

@ -42,6 +42,7 @@ public:
QString domain = QString(),
linphone::TransportType transportType = linphone::TransportType::Udp,
QString *errorMessage = nullptr);
std::shared_ptr<linphone::Account> createAccount(const QString &assistantFile);
enum RegisterType { PhoneNumber = 0, Email = 1 };
@ -58,7 +59,6 @@ public:
signals:
void registrationStateChanged(linphone::RegistrationState state);
void errorMessageChanged(const QString &errorMessage);
void newAccountCreationSucceed(QString sipAddress, RegisterType registerType, const QString &registerAddress);
void registerNewAccountFailed(const QString &error);
void tokenConversionSucceed();
@ -71,7 +71,6 @@ private:
std::shared_ptr<AccountManagerServicesModel> mAccountManagerServicesModel;
QTimer timer;
QString mCreatedSipAddress;
// std::shared_ptr<linphone::Address> mCreatedSipIdentityAddress;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -71,11 +71,12 @@ void AccountModel::setPictureUri(QString uri) {
mMonitor->setParams(params);
// Hack because Account doesn't provide callbacks on updated data
// emit pictureUriChanged(uri);
emit CoreModel::getInstance() -> defaultAccountChanged(CoreModel::getInstance()->getCore(),
CoreModel::getInstance()->getCore()->getDefaultAccount());
emit CoreModel::getInstance()->defaultAccountChanged(CoreModel::getInstance()->getCore(),
CoreModel::getInstance()->getCore()->getDefaultAccount());
}
void AccountModel::onDefaultAccountChanged() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
emit defaultAccountChanged(CoreModel::getInstance()->getCore()->getDefaultAccount() == mMonitor);
}

View file

@ -39,6 +39,7 @@ ApplicationWindow {
}
}
property bool authenticationPopupOpened: false
Component {
id: authenticationPopupComp
AuthenticationDialog{
@ -50,6 +51,8 @@ ApplicationWindow {
authenticationDialog ? authenticationDialog.result(password) : callback(password)
close()
}
onOpened: mainWindow.authenticationPopupOpened = true
onClosed: mainWindow.authenticationPopupOpened = false
}
}
@ -237,6 +240,7 @@ ApplicationWindow {
}
function reauthenticateAccount(authenticationDialog){
if (authenticationPopupOpened) return
console.log("Showing authentication dialog")
var popup = authenticationPopupComp.createObject(mainWindow, {"authenticationDialog": authenticationDialog})
popup.open()

View file

@ -168,10 +168,10 @@ AbstractDetailsLayout {
propertyOwner: account.core
}
SwitchSetting {
titleText: account.core.humaneReadableRegistrationState
subTitleText: account.core.humaneReadableRegistrationStateExplained
titleText: account?.core.humaneReadableRegistrationState
subTitleText: account?.core.humaneReadableRegistrationStateExplained
propertyName: "registerEnabled"
propertyOwner: account.core
propertyOwner: account?.core
}
RowLayout {
id:mainItem

View file

@ -50,7 +50,9 @@ AppWindow {
AccountProxy {
id: accountProxy
onHaveAccountChanged: {
initStackViewItem()
// this function can't be used like this. It will show the main page when
// trying to connect and then return to login page if connection fails.
// initStackViewItem()
}
}
StackView {

View file

@ -7,47 +7,15 @@ import Linphone
Text {
id: mainItem
color: DefaultStyle.danger_500main
opacity: 0
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
states: [
State{
name: "Visible"
PropertyChanges{target: mainItem; opacity: 1.0}
},
State{
name:"Invisible"
PropertyChanges{target: mainItem; opacity: 0.0; text: ""}
}
]
transitions: [
Transition {
from: "Visible"
to: "Invisible"
NumberAnimation {
property: "opacity"
duration: 500
}
}
]
Timer {
id: autoHideErrorMessage
interval: 2500
onTriggered: mainItem.state = "Invisible"
onTriggered: mainItem.text = ""
}
onOpacityChanged: if (opacity === 1) autoHideErrorMessage.restart()
Connections {
target: mainItem
function onTextChanged() {
if (mainItem.text.length > 0) {
mainItem.state = "Visible"
} else {
mainItem.state = "Invisible"
}
}
}
onTextChanged: if (mainItem.text.length > 0) autoHideErrorMessage.restart()
}

View file

@ -13,7 +13,7 @@ FocusScope{
property alias errorTextItem: errorText
property alias errorMessage: errorText.text
property bool enableErrorText: false
property bool errorTextVisible: errorText.opacity > 0
property bool errorTextVisible: errorText.text.length > 0
implicitHeight: layout.implicitHeight
implicitWidth: layout.implicitWidth
ColumnLayout {

View file

@ -92,11 +92,7 @@ LoginLayout {
pixelSize: 14 * DefaultStyle.dp
weight: 400* DefaultStyle.dp
}
text: "Certaines fonctionnalités nécessitent un compte Linphone, comme la messagerie de groupe, les vidéoconférences...
Ces fonctionnalités sont cachées lorsque vous vous enregistrez avec un compte SIP tiers.
Pour les activer dans un projet commercial, veuillez nous contacter. "
text: "Certaines fonctionnalités nécessitent un compte Linphone, comme la messagerie de groupe, les vidéoconférences..."
}
Text {
Layout.fillWidth: true
@ -250,8 +246,8 @@ LoginLayout {
id: errorText
Connections {
target: LoginPageCpp
function onErrorMessageChanged() {
errorText.text = LoginPageCpp.errorMessage
function onErrorMessageChanged(error) {
errorText.text = error
}
function onRegistrationStateChanged() {
if (LoginPageCpp.registrationState === LinphoneEnums.RegistrationState.Ok) {
@ -296,9 +292,11 @@ LoginLayout {
connectionButtonContent.currentIndex = 0
}
}
function onErrorMessageChanged() {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0
function onErrorMessageChanged(error) {
if (error.length != 0) {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0
}
}
}
}
@ -323,21 +321,13 @@ LoginLayout {
connectionButton.enabled = false
connectionButtonContent.currentIndex = 1
}
Shortcut {
sequences: ["Return", "Enter"]
onActivated: if(domain.activeFocus) connectionButton.trigger()
else if(username.activeFocus) password.forceActiveFocus()
else if(password.activeFocus) domain.forceActiveFocus()
}
onPressed: connectionButton.trigger()
onPressed: trigger()
KeyNavigation.up: transportCbox
}
Item {
Layout.fillHeight: true
}
}
}
centerContent: [

View file

@ -15,4 +15,4 @@ AbstractMasterDetailPage {
{title: qsTr("Général"), layout: "AccountSettingsGeneralLayout", model: account},
{title: qsTr("Paramètres de compte"), layout: "AccountSettingsParametersLayout", model: account}
]
}
}