add id and proxy address for third part connection

This commit is contained in:
Gaelle Braud 2025-09-22 10:39:48 +02:00
parent bfb46c0656
commit 471dcf131d
9 changed files with 1388 additions and 1253 deletions

View file

@ -64,22 +64,26 @@ void LoginPage::login(const QString &username,
const QString &password,
QString displayName,
QString domain,
LinphoneEnums::TransportType transportType) {
LinphoneEnums::TransportType transportType,
QString serverAddress,
QString connectionId) {
setErrorMessage("");
App::postModelAsync([=]() {
// Create on Model thread.
AccountManager *accountManager = new AccountManager();
connect(accountManager, &AccountManager::registrationStateChanged, this,
[accountManager, this](linphone::RegistrationState state, QString message) mutable {
[accountManager, this](linphone::RegistrationState state, linphone::Reason reason,
QString message) mutable {
// View thread
setRegistrationState(state);
mBadIds = reason == linphone::Reason::Forbidden;
emit reasonChanged();
switch (state) {
case linphone::RegistrationState::Failed: {
if (message.isEmpty())
//: Erreur durant la connexion
setErrorMessage(tr("default_account_connection_state_error_toast"));
else
setErrorMessage(message);
if (message.isEmpty())
//: Erreur durant la connexion, veuillez vérifier vos paramètres
setErrorMessage(tr("default_account_connection_state_error_toast"));
else setErrorMessage(message);
if (accountManager) {
accountManager->deleteLater();
accountManager = nullptr;
@ -110,9 +114,9 @@ void LoginPage::login(const QString &username,
QString error;
if (!accountManager->login(username, password, displayName, domain, LinphoneEnums::toLinphone(transportType),
&error)) {
&error, serverAddress, connectionId)) {
setErrorMessage(error);
emit accountManager->registrationStateChanged(linphone::RegistrationState::None);
emit accountManager->registrationStateChanged(linphone::RegistrationState::None, linphone::Reason::None);
}
});
}

View file

@ -35,12 +35,15 @@ public:
Q_PROPERTY(linphone::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged)
Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged)
Q_PROPERTY(bool badIds MEMBER mBadIds NOTIFY reasonChanged)
Q_INVOKABLE void login(const QString &username,
const QString &password,
QString displayName = QString(),
QString domain = QString(),
LinphoneEnums::TransportType transportType = LinphoneEnums::TransportType::Tls);
LinphoneEnums::TransportType transportType = LinphoneEnums::TransportType::Tls,
QString serverAddress = QString(),
QString connectionId = QString());
linphone::RegistrationState getRegistrationState() const;
void setRegistrationState(linphone::RegistrationState status);
@ -51,10 +54,12 @@ public:
signals:
void registrationStateChanged();
void errorMessageChanged(QString error);
void reasonChanged();
private:
linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None;
QString mErrorMessage;
bool mBadIds = false;
DECLARE_ABSTRACT_OBJECT
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,9 @@ bool AccountManager::login(QString username,
QString displayName,
QString domain,
linphone::TransportType transportType,
QString *errorMessage) {
QString *errorMessage,
QString serverAddress,
QString connectionId) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
auto factory = linphone::Factory::get();
@ -80,26 +82,30 @@ bool AccountManager::login(QString username,
auto otherParams = otherAccount->getParams();
if (otherParams->getIdentityAddress()->getUsername() == Utils::appStringToCoreString(username) &&
otherParams->getDomain() == Utils::appStringToCoreString(domain)) {
//: "Le compte est déjà connecté"
//: "The account is already connected"
*errorMessage = tr("assistant_account_login_already_connected_error");
return false;
}
}
if (!displayName.isEmpty()) identity->setDisplayName(Utils::appStringToCoreString(displayName));
if (!serverAddress.isEmpty()) {
auto linServerAddress = ToolModel::interpretUrl(serverAddress);
params->setServerAddress(linServerAddress);
}
if (!domain.isEmpty()) {
identity->setDomain(Utils::appStringToCoreString(domain));
if (QString::compare(domain, "sip.linphone.org")) {
params->setLimeServerUrl("");
auto serverAddress =
auto computedServerAddress =
factory->createAddress(Utils::appStringToCoreString(QStringLiteral("sip:%1").arg(domain)));
if (!serverAddress) {
//: "Impossible de créer l'adresse proxy. Merci de vérifier le nom de domaine."
if (!computedServerAddress) {
//: "Unable to create proxy address. Please check the domain name."
*errorMessage = tr("assistant_account_login_proxy_address_error");
return false;
}
serverAddress->setTransport(transportType);
params->setServerAddress(serverAddress);
computedServerAddress->setTransport(transportType);
params->setServerAddress(computedServerAddress);
}
}
if (params->setIdentityAddress(identity)) {
@ -107,53 +113,53 @@ bool AccountManager::login(QString username,
.arg(QStringLiteral("Unable to set identity address: `%1`."))
.arg(Utils::coreStringToAppString(identity->asStringUriOnly()));
//: "Impossible de configurer l'adresse : `%1`."
*errorMessage =
tr("assistant_account_login_address_configuration_error").arg(Utils::coreStringToAppString(identity->asStringUriOnly()));
//: "Unable to configure address: `%1`."
*errorMessage = tr("assistant_account_login_address_configuration_error")
.arg(Utils::coreStringToAppString(identity->asStringUriOnly()));
return false;
}
if (account->setParams(params)) {
//: "Impossible de configurer les paramètres du compte."
//: "Unable to configure account settings."
*errorMessage = tr("assistant_account_login_params_configuration_error");
return false;
}
auto authInfo = factory->createAuthInfo(Utils::appStringToCoreString(username), // Username.
"", // User ID.
Utils::appStringToCoreString(password), // Password.
"", // HA1.
"", // Realm.
identity->getDomain() // Domain.
auto authInfo = factory->createAuthInfo(Utils::appStringToCoreString(username), // Username.
Utils::appStringToCoreString(connectionId), // User ID.
Utils::appStringToCoreString(password), // Password.
"", // HA1.
"", // Realm.
identity->getDomain() // Domain.
);
core->addAuthInfo(authInfo);
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account);
mAccountModel->setSelf(mAccountModel);
connect(mAccountModel.get(), &AccountModel::registrationStateChanged, this,
[this, authInfo, core](const std::shared_ptr<linphone::Account> &account, linphone::RegistrationState state,
const std::string &message) {
QString errorMessage = QString::fromStdString(message);
const std::string &message) {
QString errorMessage = QString::fromStdString(message);
if (mAccountModel && account == mAccountModel->getAccount()) {
if (state == linphone::RegistrationState::Failed) {
connect(
mAccountModel.get(), &AccountModel::removed, this, [this]() { mAccountModel = nullptr; },
Qt::SingleShotConnection);
//: "Le couple identifiant mot de passe ne correspond pas"
if (account->getError() == linphone::Reason::Forbidden) errorMessage = tr("assistant_account_login_forbidden_error");
//: "Erreur durant la connexion"
else errorMessage = tr("assistant_account_login_error");
mAccountModel->removeAccount();
//: "Username and password do not match"
if (account->getError() == linphone::Reason::Forbidden)
errorMessage = tr("assistant_account_login_forbidden_error");
//: "Error during connection, please verify your parameters"
else errorMessage = tr("assistant_account_login_error");
mAccountModel->removeAccount();
} else if (state == linphone::RegistrationState::Ok) {
core->setDefaultAccount(account);
emit mAccountModel->removeListener();
mAccountModel = nullptr;
}
}
emit registrationStateChanged(state, errorMessage);
}
emit registrationStateChanged(state, account->getError(), errorMessage);
});
auto status = core->addAccount(account);
if (status == -1) {
//: "Impossible d'ajouter le compte."
//: "Unable to add account."
*errorMessage = tr("assistant_account_add_error");
core->removeAuthInfo(authInfo);
return false;

View file

@ -41,7 +41,9 @@ public:
QString displayName = QString(),
QString domain = QString(),
linphone::TransportType transportType = linphone::TransportType::Tls,
QString *errorMessage = nullptr);
QString *errorMessage = nullptr,
QString serverAddress = QString(),
QString connectionId = QString());
std::shared_ptr<linphone::Account> createAccount(const QString &assistantFile);
@ -55,7 +57,8 @@ public:
void linkNewAccountUsingCode(const QString &code, RegisterType registerType, const QString &sipAddress);
signals:
void registrationStateChanged(linphone::RegistrationState state, QString message = QString());
void
registrationStateChanged(linphone::RegistrationState state, linphone::Reason reason, QString message = QString());
void newAccountCreationSucceed(QString sipAddress, RegisterType registerType, const QString &registerAddress);
void registerNewAccountFailed(const QString &error);
void tokenConversionSucceed(QString convertedToken);

View file

@ -79,7 +79,7 @@ LoginLayout {
Component {
id: firstItem
Flickable {
width: parent.width
width: Math.round(361 * DefaultStyle.dp)
contentWidth: content.implicitWidth
contentHeight: content.implicitHeight
clip: true
@ -107,28 +107,6 @@ LoginLayout {
}
text: qsTr("Certaines fonctionnalités telles que les conversations de groupe, les vidéo-conférences, etc… nécessitent un compte %1.\n\nCes fonctionnalités seront masquées si vous utilisez un compte SIP tiers.\n\nPour les activer dans un projet commercial, merci de nous contacter.").arg(applicationName)
}
// Text {
// Layout.fillWidth: true
// Layout.preferredWidth: rootStackView.width
// wrapMode: Text.WordWrap
// color: DefaultStyle.main2_900
// font {
// pixelSize: Typography.p1.pixelSize
// weight: Typography.p1.weight
// }
// text:"Ces fonctionnalités sont cachées lorsque vous vous enregistrez avec un compte SIP tiers."
// }
// Text {
// Layout.fillWidth: true
// Layout.preferredWidth: rootStackView.width
// wrapMode: Text.WordWrap
// color: DefaultStyle.main2_900
// font {
// pixelSize: Typography.p1.pixelSize
// weight: Typography.p1.weight
// }
// text: "Pour les activer dans un projet commercial, veuillez nous contacter. "
// }
}
SmallButton {
id: openLinkButton
@ -180,7 +158,7 @@ LoginLayout {
id: secondItem
Flickable {
id: formFlickable
width: parent.width
width: Math.round(770 * DefaultStyle.dp)
contentWidth: content.implicitWidth
contentHeight: content.implicitHeight
clip: true
@ -188,211 +166,270 @@ LoginLayout {
Control.ScrollBar.vertical: scrollbar
ColumnLayout {
RowLayout {
id: content
spacing: Math.round(2 * DefaultStyle.dp)
width: formFlickable.width - scrollbar.width*2
width: formFlickable.width - scrollbar.width*2
spacing: Math.round(50 * DefaultStyle.dp)
ColumnLayout {
spacing: Math.round(8 * DefaultStyle.dp)
FormItemLayout {
id: username
//: "Nom d'utilisateur"
label: qsTr("username")
mandatory: true
enableErrorText: true
Layout.fillWidth: true
contentItem: TextField {
id: usernameEdit
isError: username.errorTextVisible || errorText.isVisible
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.down: passwordEdit
spacing: Math.round(2 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
Layout.fillHeight: true
ColumnLayout {
spacing: Math.round(22 * DefaultStyle.dp)
// alignment item
Item {
Layout.preferredHeight: advancedParametersTitle.implicitHeight
}
}
FormItemLayout {
id: password
label: qsTr("password")
mandatory: true
enableErrorText: true
Layout.fillWidth: true
contentItem: TextField {
id: passwordEdit
isError: password.errorTextVisible || errorText.isVisible
hidden: true
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: usernameEdit
KeyNavigation.down: domainEdit
}
}
FormItemLayout {
id: domain
//: "Domaine"
label: qsTr("sip_address_domain")
mandatory: true
enableErrorText: true
Layout.fillWidth: true
contentItem: TextField {
id: domainEdit
isError: domain.errorTextVisible
initialText: SettingsCpp.assistantThirdPartySipAccountDomain
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: passwordEdit
KeyNavigation.down: displayName
}
Connections {
target: SettingsCpp
function onAssistantThirdPartySipAccountDomainChanged() {
domainEdit.resetText()
ColumnLayout {
spacing: Math.round(10 * DefaultStyle.dp)
FormItemLayout {
id: username
//: "Nom d'utilisateur"
label: qsTr("username")
mandatory: true
enableErrorText: true
Layout.fillWidth: true
contentItem: TextField {
id: usernameEdit
isError: username.errorTextVisible || (LoginPageCpp.badIds && errorText.isVisible)
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.down: passwordEdit
}
}
FormItemLayout {
id: password
label: qsTr("password")
mandatory: true
enableErrorText: true
Layout.fillWidth: true
contentItem: TextField {
id: passwordEdit
isError: password.errorTextVisible || (LoginPageCpp.badIds && errorText.isVisible)
hidden: true
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: usernameEdit
KeyNavigation.down: domainEdit
}
}
FormItemLayout {
id: domain
//: "Domaine"
label: qsTr("sip_address_domain")
mandatory: true
enableErrorText: true
Layout.fillWidth: true
contentItem: TextField {
id: domainEdit
isError: domain.errorTextVisible
initialText: SettingsCpp.assistantThirdPartySipAccountDomain
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: passwordEdit
KeyNavigation.down: displayName
}
Connections {
target: SettingsCpp
function onAssistantThirdPartySipAccountDomainChanged() {
domainEdit.resetText()
}
}
}
FormItemLayout {
//: Nom d'affichage
label: qsTr("sip_address_display_name")
Layout.fillWidth: true
contentItem: TextField {
id: displayName
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: domainEdit
KeyNavigation.down: transportCbox
}
}
FormItemLayout {
//: "Transport"
label: qsTr("transport")
Layout.fillWidth: true
contentItem: ComboBox {
id: transportCbox
height: Math.round(49 * DefaultStyle.dp)
width: Math.round(360 * DefaultStyle.dp)
textRole: "text"
valueRole: "value"
model: [
{text: "TCP", value: LinphoneEnums.TransportType.Tcp},
{text: "UDP", value: LinphoneEnums.TransportType.Udp},
{text: "TLS", value: LinphoneEnums.TransportType.Tls},
{text: "DTLS", value: LinphoneEnums.TransportType.Dtls}
]
currentIndex: Utils.findIndex(model, function (entry) {
return entry.text === SettingsCpp.assistantThirdPartySipAccountTransport.toUpperCase()
})
}
}
}
}
FormItemLayout {
//: Nom d'affichage
label: qsTr("sip_address_display_name")
TemporaryText {
id: errorText
Layout.fillWidth: true
contentItem: TextField {
id: displayName
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: domainEdit
KeyNavigation.down: transportCbox
}
}
FormItemLayout {
//: "Transport"
label: qsTr("transport")
Layout.fillWidth: true
contentItem: ComboBox {
id: transportCbox
height: Math.round(49 * DefaultStyle.dp)
width: Math.round(360 * DefaultStyle.dp)
textRole: "text"
valueRole: "value"
model: [
{text: "TCP", value: LinphoneEnums.TransportType.Tcp},
{text: "UDP", value: LinphoneEnums.TransportType.Udp},
{text: "TLS", value: LinphoneEnums.TransportType.Tls},
{text: "DTLS", value: LinphoneEnums.TransportType.Dtls}
]
currentIndex: Utils.findIndex(model, function (entry) {
return entry.text === SettingsCpp.assistantThirdPartySipAccountTransport.toUpperCase()
})
}
}
}
TemporaryText {
id: errorText
Layout.fillWidth: true
Connections {
target: LoginPageCpp
function onErrorMessageChanged(error) {
errorText.setText(error)
}
}
}
BigButton {
id: connectionButton
Layout.topMargin: Math.round(15 * DefaultStyle.dp)
style: ButtonStyle.main
contentItem: StackLayout {
id: connectionButtonContent
currentIndex: 0
Text {
text: qsTr("assistant_account_login")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font {
pixelSize: Typography.b1.pixelSize
weight: Typography.b1.weight
}
color: DefaultStyle.grey_0
}
BusyIndicator {
implicitWidth: parent.height
implicitHeight: parent.height
Layout.alignment: Qt.AlignCenter
indicatorColor: DefaultStyle.grey_0
}
Connections {
target: LoginPageCpp
function onRegistrationStateChanged() {
if (LoginPageCpp.registrationState != LinphoneEnums.RegistrationState.Progress) {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0
}
}
function onErrorMessageChanged(error) {
if (error.length != 0) {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0
errorText.setText(error)
}
}
}
BigButton {
id: connectionButton
Layout.topMargin: Math.round(15 * DefaultStyle.dp)
style: ButtonStyle.main
contentItem: StackLayout {
id: connectionButtonContent
currentIndex: 0
Text {
text: qsTr("assistant_account_login")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font {
pixelSize: Typography.b1.pixelSize
weight: Typography.b1.weight
}
color: DefaultStyle.grey_0
}
BusyIndicator {
implicitWidth: parent.height
implicitHeight: parent.height
Layout.alignment: Qt.AlignCenter
indicatorColor: DefaultStyle.grey_0
}
Connections {
target: LoginPageCpp
function onRegistrationStateChanged() {
if (LoginPageCpp.registrationState != LinphoneEnums.RegistrationState.Progress) {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0
}
}
function onErrorMessageChanged(error) {
if (error.length != 0) {
connectionButton.enabled = true
connectionButtonContent.currentIndex = 0
}
}
}
}
}
function trigger() {
username.errorMessage = ""
password.errorMessage = ""
domain.errorMessage = ""
errorText.clear()
function trigger() {
username.errorMessage = ""
password.errorMessage = ""
domain.errorMessage = ""
errorText.clear()
loginDelay.restart()
}
onPressed: trigger()
KeyNavigation.up: transportCbox
Timer{
id: loginDelay
interval: 200
onTriggered: {
if (usernameEdit.text.length == 0 || passwordEdit.text.length == 0 || domainEdit.text.length == 0) {
if (usernameEdit.text.length == 0)
username.errorMessage = qsTr("assistant_account_login_missing_username")
if (passwordEdit.text.length == 0)
password.errorMessage = qsTr("assistant_account_login_missing_password")
if (domainEdit.text.length == 0)
//: "Veuillez saisir un nom de domaine
domain.errorMessage = qsTr("assistant_account_login_missing_domain")
return
loginDelay.restart()
}
onPressed: trigger()
KeyNavigation.up: transportCbox
Timer{
id: loginDelay
interval: 200
onTriggered: {
if (usernameEdit.text.length == 0 || passwordEdit.text.length == 0 || domainEdit.text.length == 0) {
if (usernameEdit.text.length == 0)
username.errorMessage = qsTr("assistant_account_login_missing_username")
if (passwordEdit.text.length == 0)
password.errorMessage = qsTr("assistant_account_login_missing_password")
if (domainEdit.text.length == 0)
//: "Veuillez saisir un nom de domaine
domain.errorMessage = qsTr("assistant_account_login_missing_domain")
return
}
console.debug("[SIPLoginPage] User: Log in")
LoginPageCpp.login(usernameEdit.text, passwordEdit.text, displayName.text, domainEdit.text,
transportCbox.currentValue, serverAddressEdit.text, connectionIdEdit.text);
connectionButton.enabled = false
connectionButtonContent.currentIndex = 1
}
console.debug("[SIPLoginPage] User: Log in")
LoginPageCpp.login(usernameEdit.text, passwordEdit.text, displayName.text, domainEdit.text, transportCbox.currentValue);
connectionButton.enabled = false
connectionButtonContent.currentIndex = 1
}
}
Item {
Layout.fillHeight: true
}
}
Item {
ColumnLayout {
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
Layout.fillHeight: true
spacing: Math.round(22 * DefaultStyle.dp)
Text {
id: advancedParametersTitle
//: Advanced parameters
text: qsTr("login_advanced_parameters_label")
font: Typography.h3m
}
ColumnLayout {
spacing: Math.round(10 * DefaultStyle.dp)
FormItemLayout {
id: serverAddress
//: "Proxy server URL"
label: qsTr("login_proxy_server_url")
Layout.fillWidth: true
contentItem: TextField {
id: serverAddressEdit
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.down: connectionIdEdit
}
}
FormItemLayout {
id: connectionId
//: "Connexion ID (if different)"
label: qsTr("login_id")
Layout.fillWidth: true
contentItem: TextField {
id: connectionIdEdit
Layout.preferredWidth: Math.round(360 * DefaultStyle.dp)
KeyNavigation.up: serverAddressEdit
}
}
}
Item{Layout.fillHeight: true}
}
Item{Layout.fillHeight: true}
}
}
}
centerContent: [
Item {
anchors.fill: parent
Control.StackView {
id: rootStackView
initialItem: SettingsCpp.assistantGoDirectlyToThirdPartySipAccountLogin ? secondItem : firstItem
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
anchors.leftMargin: Math.round(127 * DefaultStyle.dp)
width: Math.round(361 * DefaultStyle.dp)
}
ScrollBar {
id: scrollbar
z: 1
active: true
interactive: true
parent: rootStackView.currentItem
visible: parent.contentHeight > parent.height
policy: Control.ScrollBar.AsNeeded
anchors.rightMargin: -8 * DefaultStyle.dp
}
},
ScrollBar {
id: scrollbar
z: 1
active: true
interactive: true
parent: rootStackView.currentItem
visible: parent.contentHeight > parent.height
policy: Control.ScrollBar.AsNeeded
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
// Layout.leftMargin: Math.round(119 * DefaultStyle.dp)
// anchors.leftMargin: Math.round(119 * DefaultStyle.dp)
// anchors.rightMargin: -8 * DefaultStyle.dp
},
Control.StackView {
id: rootStackView
initialItem: SettingsCpp.assistantGoDirectlyToThirdPartySipAccountLogin ? secondItem : firstItem
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.leftMargin: Math.round(127 * DefaultStyle.dp)
width: currentItem ? currentItem.width : 0
},
// Item {
// id: sipItem
// // spacing: Math.round(8 * Defaultstyle.dp)
// anchors.fill: parent
// anchors.rightMargin: Math.round(50 * DefaultStyle.dp) + image.width
// },
Image {
z: -1
anchors.top: parent.top

View file

@ -9,6 +9,13 @@ QtObject {
pixelSize: Math.round(16 * DefaultStyle.dp),
weight: Math.min(Math.round(800 * DefaultStyle.dp), 1000)
})
// Title/H3m - Bloc title
property font h3m: Qt.font( {
family: DefaultStyle.defaultFont,
pixelSize: Math.round(16 * DefaultStyle.dp),
weight: Math.min(Math.round(700 * DefaultStyle.dp), 1000)
})
// Title/H3 - Bloc title
property font h3: Qt.font( {