LDAP AdressBooks settings

This commit is contained in:
Christophe Deschamps 2024-09-05 08:33:21 +00:00
parent 6f7ebb1f9f
commit 77fad7ba86
27 changed files with 1158 additions and 39 deletions

View file

@ -39,6 +39,8 @@
#include "core/account/AccountDeviceGui.hpp"
#include "core/account/AccountDeviceProxy.hpp"
#include "core/account/AccountProxy.hpp"
#include "core/address-books/LdapGui.hpp"
#include "core/address-books/LdapProxy.hpp"
#include "core/call-history/CallHistoryProxy.hpp"
#include "core/call/CallCore.hpp"
#include "core/call/CallGui.hpp"
@ -562,6 +564,8 @@ void App::initCppInterfaces() {
QLatin1String("Uncreatable"));
qmlRegisterUncreatableType<AuthenticationDialog>(Constants::MainQmlUri, 1, 0, "AuthenticationDialogCpp",
QLatin1String("Uncreatable"));
qmlRegisterType<LdapGui>(Constants::MainQmlUri, 1, 0, "LdapGui");
qmlRegisterType<LdapProxy>(Constants::MainQmlUri, 1, 0, "LdapProxy");
LinphoneEnums::registerMetaTypes();
}

View file

@ -67,6 +67,12 @@ list(APPEND _LINPHONEAPP_SOURCES
core/videoSource/VideoSourceDescriptorCore.cpp
core/videoSource/VideoSourceDescriptorGui.cpp
core/address-books/LdapCore.cpp
core/address-books/LdapGui.cpp
core/address-books/LdapProxy.cpp
core/address-books/LdapList.cpp
)
## Single Application

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LdapCore.hpp"
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(LdapCore)
QSharedPointer<LdapCore> LdapCore::create(const std::shared_ptr<linphone::Ldap> &ldap) {
auto sharedPointer = QSharedPointer<LdapCore>(new LdapCore(ldap), &QObject::deleteLater);
sharedPointer->setSelf(sharedPointer);
sharedPointer->moveToThread(App::getInstance()->thread());
return sharedPointer;
}
LdapCore::LdapCore(const std::shared_ptr<linphone::Ldap> &ldap) : QObject(nullptr) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mLdapModel = Utils::makeQObject_ptr<LdapModel>(ldap);
INIT_CORE_MEMBER(Enabled, mLdapModel)
INIT_CORE_MEMBER(Server, mLdapModel)
INIT_CORE_MEMBER(BindDn, mLdapModel)
INIT_CORE_MEMBER(Password, mLdapModel)
INIT_CORE_MEMBER(AuthMethod, mLdapModel)
INIT_CORE_MEMBER(Tls, mLdapModel)
INIT_CORE_MEMBER(ServerCertificatesVerificationMode, mLdapModel)
INIT_CORE_MEMBER(BaseObject, mLdapModel)
INIT_CORE_MEMBER(Filter, mLdapModel)
INIT_CORE_MEMBER(MaxResults, mLdapModel)
INIT_CORE_MEMBER(Timeout, mLdapModel)
INIT_CORE_MEMBER(Delay, mLdapModel)
INIT_CORE_MEMBER(MinChars, mLdapModel)
INIT_CORE_MEMBER(NameAttribute, mLdapModel)
INIT_CORE_MEMBER(SipAttribute, mLdapModel)
INIT_CORE_MEMBER(SipDomain, mLdapModel)
INIT_CORE_MEMBER(DebugLevel, mLdapModel)
}
LdapCore::~LdapCore() {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
}
void LdapCore::save() {
mLdapModelConnection->invokeToModel([this]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mLdapModel->save();
});
}
void LdapCore::remove() {
mLdapModelConnection->invokeToModel([this]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mLdapModel->remove();
});
}
bool LdapCore::isValid() {
return !mServer.isEmpty() && !mBaseObject.isEmpty();
}
void LdapCore::setSelf(QSharedPointer<LdapCore> me) {
mLdapModelConnection = QSharedPointer<SafeConnection<LdapCore, LdapModel>>(
new SafeConnection<LdapCore, LdapModel>(me, mLdapModel), &QObject::deleteLater);
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, bool, enabled, Enabled)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, server, Server)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, bindDn, BindDn)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, password, Password)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, linphone::Ldap::AuthMethod,
authMethod, AuthMethod)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, bool, tls, Tls)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel,
linphone::Ldap::CertVerificationMode, serverCertificatesVerificationMode,
ServerCertificatesVerificationMode)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, baseObject, BaseObject)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, filter, Filter)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, int, maxResults, MaxResults)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, int, timeout, Timeout)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, int, delay, Delay)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, int, minChars, MinChars)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, nameAttribute,
NameAttribute)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, sipAttribute,
SipAttribute)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, QString, sipDomain, SipDomain)
DEFINE_CORE_GETSET_CONNECT(mLdapModelConnection, LdapCore, LdapModel, mLdapModel, linphone::Ldap::DebugLevel,
debugLevel, DebugLevel)
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LDAP_CORE_H_
#define LDAP_CORE_H_
#include "model/address-books/LdapModel.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QObject>
#include <QSharedPointer>
#include <linphone++/linphone.hh>
class LdapCore : public QObject, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<LdapCore> create(const std::shared_ptr<linphone::Ldap> &ldap);
LdapCore(const std::shared_ptr<linphone::Ldap> &ldap);
~LdapCore();
void setSelf(QSharedPointer<LdapCore> me);
Q_INVOKABLE void remove();
Q_INVOKABLE void save();
Q_INVOKABLE bool isValid();
DECLARE_CORE_GETSET(bool, enabled, Enabled)
DECLARE_CORE_GETSET(QString, server, Server)
DECLARE_CORE_GETSET(QString, bindDn, BindDn)
DECLARE_CORE_GETSET(QString, password, Password)
DECLARE_CORE_GETSET(linphone::Ldap::AuthMethod, authMethod, AuthMethod)
DECLARE_CORE_GETSET(bool, tls, Tls)
DECLARE_CORE_GETSET(linphone::Ldap::CertVerificationMode,
serverCertificatesVerificationMode,
ServerCertificatesVerificationMode)
DECLARE_CORE_GETSET(QString, baseObject, BaseObject)
DECLARE_CORE_GETSET(QString, filter, Filter)
DECLARE_CORE_GETSET(int, maxResults, MaxResults)
DECLARE_CORE_GETSET(int, timeout, Timeout)
DECLARE_CORE_GETSET(int, delay, Delay)
DECLARE_CORE_GETSET(int, minChars, MinChars)
DECLARE_CORE_GETSET(QString, nameAttribute, NameAttribute)
DECLARE_CORE_GETSET(QString, sipAttribute, SipAttribute)
DECLARE_CORE_GETSET(QString, sipDomain, SipDomain)
DECLARE_CORE_GETSET(linphone::Ldap::DebugLevel, debugLevel, DebugLevel)
private:
std::shared_ptr<LdapModel> mLdapModel;
QSharedPointer<SafeConnection<LdapCore, LdapModel>> mLdapModelConnection;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(LdapCore *)
#endif

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LdapGui.hpp"
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(LdapGui)
LdapGui::LdapGui(QObject *parent) : QObject(parent) {
mustBeInMainThread(getClassName());
App::postModelSync([this]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mCore = LdapCore::create(nullptr);
});
}
LdapGui::LdapGui(QSharedPointer<LdapCore> core) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
mCore = core;
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
}
LdapGui::~LdapGui() {
mustBeInMainThread("~" + getClassName());
}
LdapCore *LdapGui::getCore() const {
return mCore.get();
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LDAP_GUI_H_
#define LDAP_GUI_H_
#include "LdapCore.hpp"
#include <QObject>
#include <QSharedPointer>
class LdapGui : public QObject, public AbstractObject {
Q_OBJECT
Q_PROPERTY(LdapCore *core READ getCore CONSTANT)
public:
LdapGui(QObject *parent = nullptr);
LdapGui(QSharedPointer<LdapCore> core);
~LdapGui();
LdapCore *getCore() const;
QSharedPointer<LdapCore> mCore;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LdapList.hpp"
#include "LdapGui.hpp"
#include "core/App.hpp"
#include "model/object/VariantObject.hpp"
#include <QSharedPointer>
#include <linphone++/linphone.hh>
// =============================================================================
DEFINE_ABSTRACT_OBJECT(LdapList)
QSharedPointer<LdapList> LdapList::create() {
auto model = QSharedPointer<LdapList>(new LdapList(), &QObject::deleteLater);
model->moveToThread(App::getInstance()->thread());
model->setSelf(model);
return model;
}
QSharedPointer<LdapCore> LdapList::createLdapCore(const std::shared_ptr<linphone::Ldap> &ldap) {
auto LdapCore = LdapCore::create(ldap);
return LdapCore;
}
LdapList::LdapList(QObject *parent) : ListProxy(parent) {
mustBeInMainThread(getClassName());
}
LdapList::~LdapList() {
mustBeInMainThread("~" + getClassName());
mModelConnection = nullptr;
}
void LdapList::setSelf(QSharedPointer<LdapList> me) {
mModelConnection = QSharedPointer<SafeConnection<LdapList, CoreModel>>(
new SafeConnection<LdapList, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
mModelConnection->makeConnectToCore(&LdapList::lUpdate, [this]() {
mModelConnection->invokeToModel([this]() {
QList<QSharedPointer<LdapCore>> *ldaps = new QList<QSharedPointer<LdapCore>>();
mustBeInLinphoneThread(getClassName());
for (auto ldap : CoreModel::getInstance()->getCore()->getLdapList()) {
auto model = createLdapCore(ldap);
ldaps->push_back(model);
}
mModelConnection->invokeToCore([this, ldaps]() {
mustBeInMainThread(getClassName());
resetData();
add(*ldaps);
delete ldaps;
});
});
});
emit lUpdate();
}
void LdapList::removeAllEntries() {
beginResetModel();
for (auto it = mList.rbegin(); it != mList.rend(); ++it) {
auto ldap = it->objectCast<LdapCore>();
ldap->remove();
}
mList.clear();
endResetModel();
}
void LdapList::remove(const int &row) {
beginRemoveRows(QModelIndex(), row, row);
auto item = mList[row].objectCast<LdapCore>();
item->remove();
mList.takeAt(row);
endRemoveRows();
}
QVariant LdapList::data(const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
if (role == Qt::DisplayRole) {
return QVariant::fromValue(new LdapGui(mList[row].objectCast<LdapCore>()));
}
return QVariant();
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LDAP_LIST_H_
#define LDAP_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QLocale>
class LdapCore;
class CoreModel;
// =============================================================================
class LdapList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<LdapList> create();
// Create a LdapCore and make connections to List.
QSharedPointer<LdapCore> createLdapCore(const std::shared_ptr<linphone::Ldap> &ldap);
LdapList(QObject *parent = Q_NULLPTR);
~LdapList();
void setSelf(QSharedPointer<LdapList> me);
void removeAllEntries();
void remove(const int &row);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void lUpdate();
private:
QSharedPointer<SafeConnection<LdapList, CoreModel>> mModelConnection;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LdapProxy.hpp"
#include "LdapGui.hpp"
#include "LdapList.hpp"
DEFINE_ABSTRACT_OBJECT(LdapProxy)
LdapProxy::LdapProxy(QObject *parent) : SortFilterProxy(parent) {
mLdapList = LdapList::create();
setSourceModel(mLdapList.get());
}
LdapProxy::~LdapProxy() {
setSourceModel(nullptr);
}
QString LdapProxy::getFilterText() const {
return mFilterText;
}
void LdapProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
mFilterText = filter;
invalidate();
emit filterTextChanged();
}
}
void LdapProxy::removeAllEntries() {
static_cast<LdapList *>(sourceModel())->removeAllEntries();
}
void LdapProxy::removeEntriesWithFilter() {
std::list<QSharedPointer<LdapCore>> itemList(rowCount());
for (auto i = rowCount() - 1; i >= 0; --i) {
auto item = getItemAt<LdapList, LdapCore>(i);
itemList.emplace_back(item);
}
for (auto item : itemList) {
mLdapList->ListProxy::remove(item.get());
if (item) item->remove();
}
}
bool LdapProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
return true;
}
bool LdapProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = getItemAt<LdapList, LdapCore>(left.row());
auto r = getItemAt<LdapList, LdapCore>(right.row());
return l->mSipDomain < r->mSipDomain;
}
void LdapProxy::updateView() {
mLdapList->lUpdate();
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LDAP_PROXY_H_
#define LDAP_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "LdapGui.hpp"
#include "LdapList.hpp"
#include "tool/AbstractObject.hpp"
// =============================================================================
class LdapProxy : public SortFilterProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public:
LdapProxy(QObject *parent = Q_NULLPTR);
~LdapProxy();
QString getFilterText() const;
void setFilterText(const QString &filter);
Q_INVOKABLE void removeAllEntries();
Q_INVOKABLE void removeEntriesWithFilter();
Q_INVOKABLE void updateView();
signals:
void filterTextChanged();
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
QString mFilterText;
QSharedPointer<LdapList> mLdapList;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -40,6 +40,8 @@ list(APPEND _LINPHONEAPP_SOURCES
model/tool/ToolModel.cpp
model/videoSource/VideoSourceDescriptorModel.cpp
model/address-books/LdapModel.cpp
)
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "LdapModel.hpp"
#include "model/core/CoreModel.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(LdapModel)
LdapModel::LdapModel(const std::shared_ptr<linphone::Ldap> &ldap, QObject *parent) {
mustBeInLinphoneThread(getClassName());
if (ldap) {
mLdap = ldap;
mLdapParamsClone = mLdap->getParams()->clone();
} else {
mLdap = nullptr;
mLdapParamsClone = CoreModel::getInstance()->getCore()->createLdapParams();
mLdapParamsClone->setTimeout(5);
mLdapParamsClone->setDelay(2000);
mLdapParamsClone->setMinChars(3);
mLdapParamsClone->enableTls(true);
}
}
LdapModel::~LdapModel() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
}
void LdapModel::save() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
if (mLdap)
CoreModel::getInstance()->getCore()->removeLdap(
mLdap); // Need to do remove/add when updating, as setParams on existing one also adds it to core.
mLdap = CoreModel::getInstance()->getCore()->createLdapWithParams(mLdapParamsClone);
CoreModel::getInstance()->getCore()->addLdap(mLdap);
lDebug() << log().arg("LDAP Server saved");
mLdapParamsClone = mLdap->getParams()->clone();
emit saved();
}
void LdapModel::remove() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->removeLdap(mLdap);
lDebug() << log().arg("LDAP Server removed");
emit removed();
}
DEFINE_GETSET(LdapModel, bool, enabled, Enabled, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, server, Server, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, bindDn, BindDn, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, password, Password, mLdapParamsClone)
DEFINE_GETSET(LdapModel, linphone::Ldap::AuthMethod, authMethod, AuthMethod, mLdapParamsClone)
DEFINE_GETSET_ENABLED(LdapModel, tls, Tls, mLdapParamsClone)
DEFINE_GETSET(LdapModel,
linphone::Ldap::CertVerificationMode,
serverCertificatesVerificationMode,
ServerCertificatesVerificationMode,
mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, baseObject, BaseObject, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, filter, Filter, mLdapParamsClone)
DEFINE_GETSET(LdapModel, int, maxResults, MaxResults, mLdapParamsClone)
DEFINE_GETSET(LdapModel, int, timeout, Timeout, mLdapParamsClone)
DEFINE_GETSET(LdapModel, int, delay, Delay, mLdapParamsClone)
DEFINE_GETSET(LdapModel, int, minChars, MinChars, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, nameAttribute, NameAttribute, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, sipAttribute, SipAttribute, mLdapParamsClone)
DEFINE_GETSET_MODEL_STRING(LdapModel, sipDomain, SipDomain, mLdapParamsClone)
DEFINE_GETSET(LdapModel, linphone::Ldap::DebugLevel, debugLevel, DebugLevel, mLdapParamsClone)

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LDAP_MODEL_H_
#define LDAP_MODEL_H_
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class LdapModel : public QObject, public AbstractObject {
Q_OBJECT
public:
LdapModel(const std::shared_ptr<linphone::Ldap> &ldap, QObject *parent = nullptr);
~LdapModel();
void setDefaultParams();
void save();
void remove();
DECLARE_GETSET(bool, enabled, Enabled)
DECLARE_GETSET(QString, server, Server)
DECLARE_GETSET(QString, bindDn, BindDn)
DECLARE_GETSET(QString, password, Password)
DECLARE_GETSET(linphone::Ldap::AuthMethod, authMethod, AuthMethod)
DECLARE_GETSET(bool, tls, Tls)
DECLARE_GETSET(linphone::Ldap::CertVerificationMode,
serverCertificatesVerificationMode,
ServerCertificatesVerificationMode)
DECLARE_GETSET(QString, baseObject, BaseObject)
DECLARE_GETSET(QString, filter, Filter)
DECLARE_GETSET(int, maxResults, MaxResults)
DECLARE_GETSET(int, timeout, Timeout)
DECLARE_GETSET(int, delay, Delay)
DECLARE_GETSET(int, minChars, MinChars)
DECLARE_GETSET(QString, nameAttribute, NameAttribute)
DECLARE_GETSET(QString, sipAttribute, SipAttribute)
DECLARE_GETSET(QString, sipDomain, SipDomain)
DECLARE_GETSET(linphone::Ldap::DebugLevel, debugLevel, DebugLevel)
signals:
void saved();
void removed();
private:
std::shared_ptr<linphone::Ldap> mLdap;
std::shared_ptr<linphone::LdapParams> mLdapParamsClone;
DECLARE_ABSTRACT_OBJECT
};
#endif

View file

@ -126,6 +126,50 @@ public:
#define DEFINE_NOTIFY_CONFIG_READY(x, X) \
emit x##Changed(get##X());
#define DECLARE_GETSET_API(type, x, X) \
type get##X() const; \
void set##X(type data); \
Q_SIGNAL void x##Changed(type x);
#define DEFINE_GETSET(Class, type, x, X, ownerNotNull) \
type Class::get##X() const { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
return ownerNotNull->get##X(); \
} \
void Class::set##X(type data) { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
if (get##X() != data) { \
ownerNotNull->set##X(data); \
emit x##Changed(data); \
} \
}
#define DEFINE_GETSET_MODEL_STRING(Class, x, X, ownerNotNull) \
QString Class::get##X() const { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
return Utils::coreStringToAppString(ownerNotNull->get##X()); \
} \
void Class::set##X(QString data) { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
if (get##X() != data) { \
ownerNotNull->set##X(Utils::appStringToCoreString(data)); \
emit x##Changed(data); \
} \
}
#define DEFINE_GETSET_ENABLED(Class, x, X, ownerNotNull) \
bool Class::get##X() const { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
return ownerNotNull->x##Enabled(); \
} \
void Class::set##X(bool data) { \
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); \
if (get##X() != data) { \
ownerNotNull->enable##X(data); \
emit x##Changed(data); \
} \
}
class AbstractObject {
public:
virtual QString getClassName() const = 0;

View file

@ -10,7 +10,8 @@ Rectangle {
width: container.width
height: container.height
property string titleText
property var component
property var contentComponent
property var topbarOptionalComponent
property var model
color: 'white'
property var container
@ -38,12 +39,40 @@ Rectangle {
id: content
width: parent.width
spacing: 10 * DefaultStyle.dp
Text {
text: titleText
font: Typography.h3
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 20 * DefaultStyle.dp
color: DefaultStyle.main2_600
spacing: 5 * DefaultStyle.dp
Button {
id: backButton
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.preferredWidth: 24 * DefaultStyle.dp
icon.source: AppIcons.leftArrow
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
focus: true
visible: mainItem.container.depth > 1
Layout.rightMargin: 41 * DefaultStyle.dp
onClicked: {
mainItem.container.pop()
}
background: Item {
anchors.fill: parent
}
}
Text {
text: titleText
color: DefaultStyle.main2_600
font: Typography.h3
}
Item {
Layout.fillWidth: true
}
Loader {
Layout.alignment: Qt.AlignRight
sourceComponent: mainItem.topbarOptionalComponent
Layout.rightMargin: 34 * DefaultStyle.dp
}
}
Rectangle {
Layout.fillWidth: true
@ -52,9 +81,8 @@ Rectangle {
color: DefaultStyle.main2_500main
}
Loader {
id:loader
Layout.fillWidth: true
sourceComponent: mainItem.component
sourceComponent: mainItem.contentComponent
}
Item {
Layout.fillHeight: true

View file

@ -9,10 +9,10 @@ import UtilsCpp
AbstractDetailsLayout {
id: mainItem
component: main
contentComponent: content
property alias account: mainItem.model
Component {
id: main
id: content
ColumnLayout {
width: parent.width
spacing: 5 * DefaultStyle.dp
@ -229,10 +229,6 @@ AbstractDetailsLayout {
}
}
}
Component.onCompleted: {
}
Component.onDestruction: {
}
}
Rectangle {
Layout.fillWidth: true

View file

@ -9,10 +9,10 @@ import UtilsCpp
AbstractDetailsLayout {
id: mainItem
component: main
contentComponent: content
property alias account: mainItem.model
Component {
id: main
id: content
ColumnLayout {
width: parent.width
spacing: 5 * DefaultStyle.dp

View file

@ -6,10 +6,10 @@ import Linphone
import SettingsCpp 1.0
AbstractDetailsLayout {
component: settings
contentComponent: content
width: parent.width
Component {
id: settings
id: content
ColumnLayout {
width: parent.width
RowLayout {

View file

@ -0,0 +1,137 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Control
import SettingsCpp 1.0
import Linphone
AbstractDetailsLayout {
id: mainItem
contentComponent: content
function layoutUrl(name) {
return layoutsPath+"/"+name+".qml"
}
Component {
id: content
RowLayout {
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
text: qsTr("Annuaires LDAP")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
Text {
text: qsTr("Ajouter vos annuaires LDAP pour pouvoir effectuer des recherches dans la magic search bar.")
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
Layout.rightMargin: 25 * DefaultStyle.dp
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 27 * DefaultStyle.dp
Layout.leftMargin: 76 * DefaultStyle.dp
Layout.topMargin: 16 * DefaultStyle.dp
Repeater {
model: LdapProxy {
id: proxyModel
}
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft|Qt.AlignHCenter
spacing: 5 * DefaultStyle.dp
Text {
text: modelData.core.server
font: Typography.p2l
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
Layout.leftMargin: 17 * DefaultStyle.dp
}
Item {
Layout.fillWidth: true
}
Button {
background: Item{}
icon.source: AppIcons.pencil
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
contentImageColor: DefaultStyle.main2_600
onClicked: {
var ldapGui = Qt.createQmlObject('import Linphone
LdapGui{
}', mainItem)
mainItem.container.push(layoutUrl("LdapSettingsLayout"), {
titleText: qsTr("Modifier un annuaire LDAP"),
model: modelData,
container: mainItem.container,
isNew: false})
}
}
Switch {
id: switchButton
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: 17 * DefaultStyle.dp
checked: modelData.core["enabled"]
onToggled: {
binding.when = true
modelData.core.save()
}
}
Binding {
id: binding
target: modelData.core
property: "enabled"
value: switchButton.checked
when: false
}
}
onVisibleChanged: {
proxyModel.updateView()
}
Component.onCompleted: {
proxyModel.updateView()
}
}
RowLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
Item {
Layout.fillWidth: true
}
Button {
Layout.alignment: Qt.AlignRight | Qt.AlignHCenter
text: qsTr("Ajouter")
onClicked: {
var ldapGui = Qt.createQmlObject('import Linphone
LdapGui{
}', mainItem)
mainItem.container.push(layoutUrl("LdapSettingsLayout"), {
titleText: qsTr("Ajouter un annuaire LDAP"),
model: ldapGui,
container: mainItem.container,
isNew: true})
}
}
}
}
}
}
}

View file

@ -12,12 +12,14 @@ AbstractDetailsLayout {
Layout.fillHeight: true
id: mainItem
property string logsUrl
contentComponent: content
Dialog {
id: deleteLogs
text: qsTr("Les traces de débogage seront supprimées. Souhaitez-vous continuer ?")
onAccepted: SettingsCpp.cleanLogs()
}
Dialog {
id: shareLogs
text: qsTr("Les traces de débogage ont été téléversées. Comment souhaitez-vous partager le lien ? ")
@ -43,8 +45,9 @@ AbstractDetailsLayout {
}
]
}
Component {
id: debug
id: content
ColumnLayout {
spacing: 40 * DefaultStyle.dp
SwitchSetting {
@ -73,6 +76,7 @@ AbstractDetailsLayout {
}
}
}
Connections {
target: SettingsCpp
function onLogsUploadTerminated(status, url) {
@ -85,5 +89,4 @@ AbstractDetailsLayout {
}
}
}
component: debug
}

View file

@ -0,0 +1,171 @@
import QtCore
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Control
import QtQuick.Dialogs
import Linphone
import SettingsCpp 1.0
import UtilsCpp
AbstractDetailsLayout {
id: mainItem
contentComponent: content
topbarOptionalComponent: topBar
property alias ldapGui: mainItem.model
property bool isNew: false
Component {
id: topBar
RowLayout {
spacing: 20 * DefaultStyle.dp
Button {
background: Item{}
icon.source: AppIcons.trashCan
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
contentImageColor: DefaultStyle.main2_600
visible: !isNew
onClicked: {
var mainWin = UtilsCpp.getMainWindow()
mainWin.showConfirmationLambdaPopup(
qsTr("Supprimer l'annuaire LDAP ?"),
"",
function (confirmed) {
if (confirmed) {
ldapGui.core.remove()
mainItem.container.pop()
}
}
)
}
}
Button {
text: qsTr("Enregistrer")
onClicked: {
if (ldapGui.core.isValid()) {
ldapGui.core.save()
UtilsCpp.showInformationPopup(qsTr("Succès"), qsTr("L'annuaire LDAP a été sauvegardé"), true, mainWindow)
} else {
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Une erreur s'est produite, la configuration LDAP n'a pas été sauvegardée !"), false, mainWindow)
}
}
}
}
}
Component {
id: content
ColumnLayout {
width: parent.width
spacing: 5 * DefaultStyle.dp
RowLayout {
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
Layout.minimumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("Annuaires LDAP")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
}
Text {
text: qsTr("Ajouter vos annuaires LDAP pour pouvoir effectuer des recherches dans la magic search bar.")
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 20 * DefaultStyle.dp
Layout.rightMargin: 44 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
ValidatedTextField {
id: server
propertyName: "server"
propertyOwner: ldapGui.core
title: qsTr("URL du serveur (ne peut être vide)")
}
ValidatedTextField {
propertyName: "bindDn"
propertyOwner: ldapGui.core
title: qsTr("Bind DN")
}
ValidatedTextField {
propertyName: "password"
hidden: true
propertyOwner: ldapGui.core
title: qsTr("Mot de passe")
}
SwitchSetting {
titleText: qsTr("Utiliser TLS")
propertyName: "tls"
propertyOwner: ldapGui.core
}
ValidatedTextField {
propertyName: "baseObject"
propertyOwner: ldapGui.core
title: qsTr("Base de recherche (ne peut être vide)")
}
ValidatedTextField {
propertyName: "filter"
propertyOwner: ldapGui.core
title: qsTr("Filtre")
}
ValidatedTextField {
propertyName: "maxResults"
propertyOwner: ldapGui.core
validator: RegularExpressionValidator { regularExpression: /[0-9]+/ }
title: qsTr("Nombre maximum de résultats")
}
ValidatedTextField {
propertyName: "delay"
propertyOwner: ldapGui.core
validator: RegularExpressionValidator { regularExpression: /[0-9]+/ }
title: qsTr("Délai entre 2 requêtes (en millisecondes)")
}
ValidatedTextField {
propertyName: "timeout"
propertyOwner: ldapGui.core
title: qsTr("Durée maximun (en secondes)")
validator: RegularExpressionValidator { regularExpression: /[0-9]+/ }
}
ValidatedTextField {
propertyName: "minChars"
propertyOwner: ldapGui.core
title: qsTr("Nombre minimum de caractères pour la requête")
validator: RegularExpressionValidator { regularExpression: /[0-9]+/ }
}
ValidatedTextField {
propertyName: "nameAttribute"
propertyOwner: ldapGui.core
title: qsTr("Attributs de nom")
}
ValidatedTextField {
propertyName: "sipAttribute"
propertyOwner: ldapGui.core
title: qsTr("Attributs SIP")
}
ValidatedTextField {
propertyName: "sipDomain"
propertyOwner: ldapGui.core
title: qsTr("Domaine SIP")
}
}
}
}
}
}

View file

@ -6,8 +6,9 @@ import SettingsCpp 1.0
import Linphone
AbstractDetailsLayout {
contentComponent: content
Component {
id: settings
id: content
Column {
spacing: 40 * DefaultStyle.dp
SwitchSetting {
@ -18,5 +19,4 @@ AbstractDetailsLayout {
}
}
}
component: settings
}

View file

@ -23,7 +23,9 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/App/Layout/Settings/SecuritySettingsLayout.qml
view/App/Layout/Settings/CallSettingsLayout.qml
view/App/Layout/Settings/DebugSettingsLayout.qml
view/App/Layout/Settings/ContactsSettingsLayout.qml
view/App/Layout/Settings/LdapSettingsLayout.qml
view/App/Layout/Account/AccountSettingsGeneralLayout.qml
view/App/Layout/Account/AccountSettingsParametersLayout.qml

View file

@ -106,7 +106,7 @@ Rectangle{
Layout.preferredHeight: 26 * DefaultStyle.dp
Layout.fillHeight: true
Layout.leftMargin: 40 * DefaultStyle.dp
visible: true // mainItem.account.core.unreadCallNotifications > 0
visible: mainItem.account.core.unreadCallNotifications > 0
Rectangle{
id: unreadNotifications
anchors.verticalCenter: parent.verticalCenter

View file

@ -19,6 +19,10 @@ FormItemLayout {
property var isValid: function(text) {
return true;
}
property alias hidden: textField.hidden
property alias validator: textField.validator
property bool empty: mainItem.propertyOwner[mainItem.propertyName]?.length == 0
property bool canBeEmpty: true
contentItem: TextField {
id: textField
property var initialReading: true
@ -33,23 +37,29 @@ FormItemLayout {
onTriggered: textField.editingFinished()
}
onEditingFinished: {
updateText()
}
onTextChanged: {
idleTimer.restart()
updateText()
}
function updateText() {
mainItem.empty = text.length == 0
if (initialReading) {
initialReading = false
return
}
if (text.length != 0) {
if (isValid(text)) {
mainItem.errorMessage = ""
if (mainItem.propertyOwner[mainItem.propertyName] != text)
mainItem.propertyOwner[mainItem.propertyName] = text
} else {
mainItem.errorMessage = qsTr("Format non reconnu")
}
} else
if (!canBeEmpty && mainItem.empty) {
mainItem.errorMessage = qsTr("ne peut être vide")
return
}
if (isValid(text)) {
mainItem.errorMessage = ""
}
onTextChanged: {
idleTimer.restart()
if (mainItem.propertyOwner[mainItem.propertyName] != text)
mainItem.propertyOwner[mainItem.propertyName] = text
} else {
mainItem.errorMessage = qsTr("Format non reconnu")
}
}
}
}

View file

@ -11,7 +11,7 @@ AbstractMasterDetailPage {
{title: qsTr("Appels"), layout: "CallSettingsLayout"},
//{title: qsTr("Sécurité"), layout: "SecuritySettingsLayout"},
{title: qsTr("Conversations"), layout: "ChatSettingsLayout", visible: !SettingsCpp.disableChatFeature},
{title: qsTr("Contacts"), layout: "ContactSettingsLayout"},
{title: qsTr("Contacts"), layout: "ContactsSettingsLayout"},
{title: qsTr("Réunions"), layout: "MeetingsSettingsLayout", visible: !SettingsCpp.disableMeetingsFeature},
{title: qsTr("Affichage"), layout: "DisplaySettingsLayout"},
{title: qsTr("Réseau"), layout: "NetworkSettingsLayout"},

View file

@ -52,14 +52,14 @@ QtObject {
weight: 400 * DefaultStyle.dp
})
// Text/P1 - Paratraph text
// Text/P1 - Paratraph text
property font p1s: Qt.font( {
family: DefaultStyle.defaultFont,
pixelSize: 13 * DefaultStyle.dp,
weight: 400 * DefaultStyle.dp
})
// Bouton/B2 - Medium Bouton
// Button/B2 - Medium Button
property font b2: Qt.font( {
family: DefaultStyle.defaultFont,
pixelSize: 15 * DefaultStyle.dp,