Add OpenLDAP supports

- set defaults for LDAP
- add unsaving a server
- adapt design for LDAP (placement, debug and verifications options)

- Add hidden options in linphonerc to hide local sip account, start video call button and start chat button
This commit is contained in:
Julien Wadel 2021-04-01 19:51:06 +02:00
parent 77a3f294e0
commit 384bd0675a
44 changed files with 2489 additions and 44 deletions

View file

@ -163,7 +163,7 @@ endif()
if(ENABLE_BUILD_APP_PLUGINS)
file(GLOB children RELATIVE plugins plugins/*)
file(GLOB children "plugins/*")
set(dirlist "")
foreach(child ${children})
if(IS_DIRECTORY ${curdir}/${child} AND (ENABLE_BUILD_EXAMPLES OR NOT ${child} MATCHES "example"))

View file

@ -145,6 +145,9 @@ set(SOURCES
src/components/file/FileExtractor.cpp
src/components/history/HistoryModel.cpp
src/components/history/HistoryProxyModel.cpp
src/components/ldap/LdapModel.cpp
src/components/ldap/LdapListModel.cpp
src/components/ldap/LdapProxyModel.cpp
src/components/notifier/Notifier.cpp
src/components/other/clipboard/Clipboard.cpp
src/components/other/colors/Colors.cpp
@ -152,11 +155,13 @@ set(SOURCES
src/components/other/units/Units.cpp
src/components/presence/OwnPresenceModel.cpp
src/components/presence/Presence.cpp
src/components/search/SearchHandler.cpp
src/components/settings/AccountSettingsModel.cpp
src/components/settings/SettingsModel.cpp
src/components/sip-addresses/SipAddressesModel.cpp
src/components/sip-addresses/SipAddressesProxyModel.cpp
src/components/sip-addresses/SipAddressObserver.cpp
src/components/sip-addresses/SearchSipAddressesModel.cpp
src/components/sound-player/SoundPlayer.cpp
src/components/telephone-numbers/TelephoneNumbersModel.cpp
src/components/timeline/TimelineModel.cpp
@ -215,6 +220,9 @@ set(HEADERS
src/components/file/FileExtractor.hpp
src/components/history/HistoryModel.hpp
src/components/history/HistoryProxyModel.hpp
src/components/ldap/LdapModel.hpp
src/components/ldap/LdapListModel.hpp
src/components/ldap/LdapProxyModel.hpp
src/components/notifier/Notifier.hpp
src/components/other/clipboard/Clipboard.hpp
src/components/other/colors/Colors.hpp
@ -223,11 +231,13 @@ set(HEADERS
src/components/other/units/Units.hpp
src/components/presence/OwnPresenceModel.hpp
src/components/presence/Presence.hpp
src/components/search/SearchHandler.hpp
src/components/settings/AccountSettingsModel.hpp
src/components/settings/SettingsModel.hpp
src/components/sip-addresses/SipAddressesModel.hpp
src/components/sip-addresses/SipAddressesProxyModel.hpp
src/components/sip-addresses/SipAddressObserver.hpp
src/components/sip-addresses/SearchSipAddressesModel.hpp
src/components/sound-player/SoundPlayer.hpp
src/components/telephone-numbers/TelephoneNumbersModel.hpp
src/components/timeline/TimelineModel.hpp
@ -378,7 +388,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.cmake" "${CMAKE_CURRENT
# ------------------------------------------------------------------------------
include_directories(src/)
include_directories("${LINPHONE_OUTPUT_DIR}}/include/OpenGL")
include_directories("${LINPHONE_OUTPUT_DIR}/include/OpenGL")
if (CMAKE_INSTALL_RPATH)
#Retrieve lib path from a know QT executable
@ -500,7 +510,8 @@ target_link_libraries(${TARGET_NAME} ${LIBRARIES})
target_link_libraries(${TARGET_NAME} ${APP_PLUGIN})
if(WIN32)
target_link_libraries(${TARGET_NAME} wsock32 ws2_32)
find_library(LDAP_LIBRARIES NAMES ldap HINTS "${LINPHONE_OUTPUT_DIR}/lib")
target_link_libraries(${TARGET_NAME} wsock32 ws2_32 ${LDAP_LIBRARIES})
endif()
add_dependencies(${APP_LIBRARY} update_translations ${TARGET_NAME}-git-version ${APP_PLUGIN})

View file

@ -489,5 +489,9 @@
<file>ui/dev-modules/Colors/Colors.qml</file>
<file>ui/dev-modules/Units/Units.qml</file>
<file>assets/icon.ico</file>
<file>ui/views/App/Settings/SettingsLdap.qml</file>
<file>ui/views/App/Settings/SettingsLdapDescription.qml</file>
<file>ui/views/App/Settings/Dialogs/SettingsLdapEdit.qml</file>
<file>ui/views/App/Settings/Dialogs/SettingsLdapEdit.js</file>
</qresource>
</RCC>

View file

@ -579,6 +579,8 @@ void App::registerTypes () {
qRegisterMetaType<shared_ptr<linphone::ProxyConfig>>();
qRegisterMetaType<ChatModel::EntryType>();
qRegisterMetaType<shared_ptr<linphone::SearchResult>>();
qRegisterMetaType<std::list<std::shared_ptr<linphone::SearchResult> > >();
registerType<AssistantModel>("AssistantModel");
registerType<AuthenticationNotifier>("AuthenticationNotifier");
@ -593,7 +595,10 @@ void App::registerTypes () {
registerType<FileDownloader>("FileDownloader");
registerType<FileExtractor>("FileExtractor");
registerType<HistoryProxyModel>("HistoryProxyModel");
registerType<LdapProxyModel>("LdapProxyModel");
registerType<SipAddressesProxyModel>("SipAddressesProxyModel");
registerType<SearchSipAddressesModel>("SearchSipAddressesModel");
registerType<SoundPlayer>("SoundPlayer");
registerType<TelephoneNumbersModel>("TelephoneNumbersModel");
@ -610,6 +615,7 @@ void App::registerTypes () {
registerUncreatableType<ContactModel>("ContactModel");
registerUncreatableType<ContactsImporterModel>("ContactsImporterModel");
registerUncreatableType<HistoryModel>("HistoryModel");
registerUncreatableType<LdapModel>("LdapModel");
registerUncreatableType<SipAddressObserver>("SipAddressObserver");
registerUncreatableType<VcardModel>("VcardModel");
}
@ -625,6 +631,7 @@ void App::registerSharedTypes () {
registerSharedSingletonType<CallsListModel, &CoreManager::getCallsListModel>("CallsListModel");
registerSharedSingletonType<ContactsListModel, &CoreManager::getContactsListModel>("ContactsListModel");
registerSharedSingletonType<ContactsImporterListModel, &CoreManager::getContactsImporterListModel>("ContactsImporterListModel");
registerSharedSingletonType<LdapListModel, &CoreManager::getLdapListModel>("LdapListModel");
}
void App::registerToolTypes () {

View file

@ -46,12 +46,16 @@
#include "file/FileDownloader.hpp"
#include "file/FileExtractor.hpp"
#include "history/HistoryProxyModel.hpp"
#include "ldap/LdapModel.hpp"
#include "ldap/LdapListModel.hpp"
#include "ldap/LdapProxyModel.hpp"
#include "notifier/Notifier.hpp"
#include "presence/OwnPresenceModel.hpp"
#include "settings/AccountSettingsModel.hpp"
#include "settings/SettingsModel.hpp"
#include "sip-addresses/SipAddressesModel.hpp"
#include "sip-addresses/SipAddressesProxyModel.hpp"
#include "sip-addresses/SearchSipAddressesModel.hpp"
#include "sound-player/SoundPlayer.hpp"
#include "telephone-numbers/TelephoneNumbersModel.hpp"
#include "timeline/TimelineModel.hpp"

View file

@ -35,6 +35,10 @@
#include "utils/MediastreamerUtils.hpp"
#include "utils/Utils.hpp"
//#include "linphone/api/c-magic-search.h"
#include "linphone/api/c-search-result.h"
//#include "linphone/api/friends.h"
// =============================================================================
@ -45,10 +49,33 @@ namespace {
constexpr char AutoAnswerObjectName[] = "auto-answer-timer";
}
CallModel::CallModel (shared_ptr<linphone::Call> call) {
void CallModel::searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> results){
bool found = false;
for(auto it = results.begin() ; it != results.end() && !found ; ++it){
if((*it)->getFriend()){
if((*it)->getFriend()->getAddress()->weakEqual(mRemoteAddress)){
setRemoteDisplayName((*it)->getFriend()->getName());
found = true;
}
}else{
if((*it)->getAddress()->weakEqual(mRemoteAddress)){
setRemoteDisplayName((*it)->getAddress()->getDisplayName());
found = true;
}
}
}
}
void CallModel::setRemoteDisplayName(const std::string& name){
mRemoteAddress->setDisplayName(name);
emit fullPeerAddressChanged();
}
CallModel::CallModel (shared_ptr<linphone::Call> call){
Q_CHECK_PTR(call);
mCall = call;
mCall->setData("call-model", *this);
updateIsInConference();
@ -78,23 +105,34 @@ CallModel::CallModel (shared_ptr<linphone::Call> call) {
coreHandlers, &CoreHandlers::callEncryptionChanged,
this, &CallModel::handleCallEncryptionChanged
);
// Update fields
mMagicSearch = CoreManager::getInstance()->getCore()->createMagicSearch();
mSearch = std::make_shared<SearchHandler>(this);
QObject::connect(mSearch.get(), SIGNAL(searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> )), this, SLOT(searchReceived(std::list<std::shared_ptr<linphone::SearchResult>>)));
mMagicSearch->addListener(mSearch);
mRemoteAddress = mCall->getRemoteAddress()->clone();
mMagicSearch->getContactListFromFilterAsync(mRemoteAddress->getUsername(),mRemoteAddress->getDomain());
}
CallModel::~CallModel () {
mCall->unsetData("call-model");
mMagicSearch->removeListener(mSearch);
mCall->unsetData("call-model");
}
// -----------------------------------------------------------------------------
QString CallModel::getPeerAddress () const {
return Utils::coreStringToAppString(mCall->getRemoteAddress()->asStringUriOnly());
return Utils::coreStringToAppString(mRemoteAddress->asStringUriOnly());
}
QString CallModel::getLocalAddress () const {
return Utils::coreStringToAppString(mCall->getCallLog()->getLocalAddress()->asStringUriOnly());
}
QString CallModel::getFullPeerAddress () const {
return QString::fromStdString(mCall->getRemoteAddress()->asString());
return QString::fromStdString(mRemoteAddress->asString());
}
QString CallModel::getFullLocalAddress () const {

View file

@ -23,7 +23,7 @@
#include <QObject>
#include <linphone++/linphone.hh>
#include "../search/SearchHandler.hpp"
// =============================================================================
@ -32,7 +32,7 @@ class CallModel : public QObject {
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT);
Q_PROPERTY(QString localAddress READ getLocalAddress CONSTANT);
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress CONSTANT);
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged);
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress CONSTANT);
Q_PROPERTY(CallStatus status READ getStatus NOTIFY statusChanged);
@ -132,8 +132,17 @@ public:
Q_INVOKABLE void updateStreams ();
Q_INVOKABLE void toggleSpeakerMute();
void setRemoteDisplayName(const std::string& name);
static constexpr int DtmfSoundDelay = 200;
std::shared_ptr<linphone::Call> mCall;
std::shared_ptr<linphone::Address> mRemoteAddress;
std::shared_ptr<linphone::MagicSearch> mMagicSearch;
public slots:
void searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> results);
signals:
void callErrorChanged (const QString &callError);
@ -149,10 +158,14 @@ signals:
void microVolumeGainChanged (float volume);
void cameraFirstFrameReceived (unsigned int width, unsigned int height);
void fullPeerAddressChanged();
private:
void handleCallEncryptionChanged (const std::shared_ptr<linphone::Call> &call);
void handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state);
void accept (bool withVideo);
@ -230,8 +243,8 @@ private:
QVariantList mAudioStats;
QVariantList mVideoStats;
std::shared_ptr<SearchHandler> mSearch;
std::shared_ptr<linphone::Call> mCall;
};
#endif // CALL_MODEL_H_

View file

@ -34,6 +34,7 @@
#include "components/contacts/ContactsListModel.hpp"
#include "components/contacts/ContactsImporterListModel.hpp"
#include "components/history/HistoryModel.hpp"
#include "components/ldap/LdapListModel.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "components/sip-addresses/SipAddressesModel.hpp"
@ -101,6 +102,7 @@ void CoreManager::initCoreManager(){
mContactsListModel = new ContactsListModel(this);
mContactsImporterListModel = new ContactsImporterListModel(this);
mAccountSettingsModel = new AccountSettingsModel(this);
mLdapListModel = new LdapListModel(this);
mSettingsModel = new SettingsModel(this);
mSipAddressesModel = new SipAddressesModel(this);
mEventCountNotifier = new EventCountNotifier(this);
@ -108,6 +110,10 @@ void CoreManager::initCoreManager(){
QObject::connect(mEventCountNotifier, &EventCountNotifier::eventCountChanged,this, &CoreManager::eventCountChanged);
migrate();
mStarted = true;
//std::list<std::string> dns;
//dns.push_back("10.0.3.50");
//mCore->setDnsServers(dns);
qInfo() << QStringLiteral("CoreManager initialized");
emit coreManagerInitialized();
}

View file

@ -39,10 +39,12 @@ class ContactsImporterListModel;
class CoreHandlers;
class EventCountNotifier;
class HistoryModel;
class LdapListModel;
class SettingsModel;
class SipAddressesModel;
class VcardModel;
class CoreManager : public QObject {
Q_OBJECT;
@ -116,7 +118,9 @@ public:
Q_CHECK_PTR(mAccountSettingsModel);
return mAccountSettingsModel;
}
LdapListModel *getLdapListModel() const{
return mLdapListModel;
}
static CoreManager *getInstance ();
// ---------------------------------------------------------------------------
@ -199,6 +203,7 @@ private:
QHash<QPair<QString, QString>, std::weak_ptr<ChatModel>> mChatModels;
HistoryModel * mHistoryModel = nullptr;
LdapListModel *mLdapListModel = nullptr;
QTimer *mCbsTimer = nullptr;

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2010-2020 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 <QDateTime>
#include <QElapsedTimer>
#include <QUrl>
#include <QtDebug>
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "utils/LinphoneUtils.hpp"
#include "utils/Utils.hpp"
#include "LdapListModel.hpp"
// =============================================================================
using namespace std;
LdapListModel::LdapListModel (QObject *parent) : QAbstractListModel(parent) {
initLdap();
}
// -----------------------------------------------------------------------------
void LdapListModel::reset(){
resetInternalData();
initLdap();
}
int LdapListModel::rowCount (const QModelIndex &) const {
return mServers.count();
}
QHash<int, QByteArray> LdapListModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$ldapServer";
return roles;
}
QVariant LdapListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mServers.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mServers[row]);
return QVariant();
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
bool LdapListModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
}
bool LdapListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mServers.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
delete mServers.takeAt(row);
endRemoveRows();
return true;
}
// -----------------------------------------------------------------------------
void LdapListModel::initLdap () {
CoreManager *coreManager = CoreManager::getInstance();
auto lConfig = coreManager->getCore()->getConfig();
auto bcSections = lConfig->getSectionsNamesList();
for(auto itSections = bcSections.begin(); itSections != bcSections.end(); ++itSections) {
LdapModel * ldap = new LdapModel();
if(ldap->load(*itSections)){
mServers.append(ldap);
}else
delete ldap;
}
}
void LdapListModel::enable(int id, bool status){
if( mServers[id]->isValid()){
QVariantMap config = mServers[id]->getConfig();
config["enable"] = status;
mServers[id]->setConfig(config);
mServers[id]->save();
}
emit dataChanged(index(id, 0), index(id, 0));
}
void LdapListModel::add(){
int row = mServers.count();
beginInsertRows(QModelIndex(), row, row);
auto ldap= new LdapModel(row);
ldap->init();
mServers << ldap;
endInsertRows();
//emit dataChanged(index(row, 0), index(row, 0));
resetInternalData();
}
void LdapListModel::remove (LdapModel *ldap) {
int index = mServers.indexOf(ldap);
if (index >=0){
ldap->unsave();
removeRow(index);
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2010-2020 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_MODEL_H_
#define LDAP_LIST_MODEL_H_
#include <QAbstractListModel>
#include <QDateTime>
#include "LdapModel.hpp"
// =============================================================================
class CoreHandlers;
class LdapListModel : public QAbstractListModel {
Q_OBJECT
public:
LdapListModel (QObject *parent = Q_NULLPTR);
void reset();
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE void enable(int id, bool status);
Q_INVOKABLE void add();
Q_INVOKABLE void remove (LdapModel *importer);
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
// ---------------------------------------------------------------------------
void initLdap ();
QList<LdapModel*> mServers;
};
#endif // LDAP_LIST_MODEL_H_

View file

@ -0,0 +1,349 @@
/*
* Copyright (c) 2010-2020 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 <QDateTime>
#include <QElapsedTimer>
#include <QUrl>
#include <QtDebug>
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "utils/LinphoneUtils.hpp"
#include "utils/Utils.hpp"
#include "LdapModel.hpp"
// =============================================================================
using namespace std;
LdapModel::LdapModel (const int& id,QObject *parent ) : QObject(parent), mId(id){
mIsValid = false;
mMaxResults = 50;
mDebug = false;
mVerifyServerCertificates = -1;
mUseTls = true;
mUseSal = false;
mServer = "ldap://ldap.example.org";
mConfig["enable"] = "0";
}
void LdapModel::init(){
set();
unset();
}
bool LdapModel::isValid(){
bool valid = mServerFieldError==""
&& mMaxResultsFieldError==""
&& mPasswordFieldError==""
&& mBindDnFieldError==""
&& mBaseObjectFieldError==""
&& mFilterFieldError==""
&& mNameAttributesFieldError==""
&& mSipAttributesFieldError==""
&& mSipSchemeFieldError==""
&& mSipDomainFieldError=="";
if( valid != mIsValid){
mIsValid = valid;
emit isValidChanged();
}
return mIsValid;
}
void LdapModel::save(){
if(isValid()){
set();
CoreManager *coreManager = CoreManager::getInstance();
auto lConfig = coreManager->getCore()->getConfig();
std::string section = ("ldap_"+QString::number(mId)).toStdString();
lConfig->cleanSection(section);
for(auto it = mConfig.begin() ; it != mConfig.end() ; ++it)
lConfig->setString(section, it.key().toStdString(), it.value().toString().toStdString());
}
}
void LdapModel::unsave(){
if(mId>=0){
CoreManager *coreManager = CoreManager::getInstance();
auto lConfig = coreManager->getCore()->getConfig();
std::string section = ("ldap_"+QString::number(mId)).toStdString();
lConfig->cleanSection(section);
}
}
bool LdapModel::load(const std::string& section){
bool ok = false;
CoreManager *coreManager = CoreManager::getInstance();
auto lConfig = coreManager->getCore()->getConfig();
std::string sectionName;
size_t i = section.length()-1;
while(i>0 && section[i] != '_')// Get the name strip number
--i;
if(i>0){
sectionName = section.substr(0,i);
mId = atoi(section.substr(i+1).c_str());
}else{
sectionName = section;
mId = 0;
}
if(sectionName == "ldap"){
mConfig.clear();
auto keys = lConfig->getKeysNamesList(section);
for(auto itKeys = keys.begin() ; itKeys != keys.end() ; ++itKeys){
mConfig[QString::fromStdString(*itKeys)] = QString::fromStdString(lConfig->getString(section, *itKeys, ""));
}
unset();
ok = true;
}
return ok;
}
QVariantMap LdapModel::getConfig(){
return mConfig;
}
void LdapModel::setConfig(const QVariantMap& config){
mConfig = config;
emit configChanged();
}
void LdapModel::set(){
mConfig["server"] = mServer;
mConfig["display_name"] = mDisplayName;
mConfig["use_sal"] = (mUseSal?"1":"0");
mConfig["use_tls"] = (mUseTls?"1":"0");
mConfig["server"] = mServer;
mConfig["max_results"] = mMaxResults;
mConfig["password"] = mPassword;
mConfig["bind_dn"] = mBindDn;
mConfig["base_object"] = mBaseObject;
mConfig["filter"] = mFilter;
mConfig["name_attribute"] = mNameAttributes;
mConfig["sip_attribute"] = mSipAttributes;
mConfig["sip_scheme"] = mSipScheme;
mConfig["sip_domain"] = mSipDomain;
mConfig["debug"] = (mDebug?"1":"0");
mConfig["verify_server_certificates"] = mVerifyServerCertificates;
}
void LdapModel::unset(){
mServer = mConfig["server"].toString();
mDisplayName = mConfig["display_name"].toString();
mUseTls = mConfig["use_tls"].toString() == "1";
mUseSal = mConfig["use_sal"].toString() == "1";
mMaxResults = mConfig["max_results"].toInt();
mPassword = mConfig["password"].toString();
mBindDn = mConfig["bind_dn"].toString();
mBaseObject = mConfig["base_object"].toString();
mFilter = mConfig["filter"].toString();
mNameAttributes = mConfig["name_attribute"].toString();
mSipAttributes = mConfig["sip_attribute"].toString();
mSipScheme = mConfig["sip_scheme"].toString();
mSipDomain = mConfig["sip_domain"].toString();
mDebug = mConfig["debug"].toString() == "1";
mVerifyServerCertificates = mConfig["verify_server_certificates"].toInt();
testServerField();
testMaxResultsField();
testPasswordField();
testBindDnField();
testBaseObjectField();
testFilterField();
testNameAttributesField();
testSipAttributesField();
testSipSchemeField();
testSipDomainField();
isValid();
}
bool LdapModel::isEnabled(){
return mConfig["enable"].toString() == "1";
}
void LdapModel::setEnabled(const bool& data){
if(isValid()){
mConfig["enable"] = (data?"1":"0");
save();
}else
mConfig["enable"] = "0";
emit enabledChanged();
}
//------------------------------------------------------------------------------------
void LdapModel::setServer(const QString& server){
mServer = server;
testServerField();
emit serverChanged();
}
void LdapModel::testServerField(){
QString valid;
if(mServer == "")
valid = "Server must not be empty";
else{
QUrl url(mServer);
if(!url.isValid())
valid = "Server is not an URL";
else if(url.scheme().left(4) != "ldap")
valid = "URL must begin by a ldap scheme";
else
valid = "";
}
if( valid != mServerFieldError){
mServerFieldError = valid;
emit serverFieldErrorChanged();
isValid();
}
}
void LdapModel::setMaxResults(const int& data){
mMaxResults = data;
testMaxResultsField();
emit maxResultsChanged();
}
void LdapModel::testMaxResultsField(){
QString valid;
if(mMaxResults <= 0)
valid = "Max Results must be greater than 0";
else
valid = "";
if( valid != mMaxResultsFieldError){
mMaxResultsFieldError = valid;
emit maxResultsFieldErrorChanged();
isValid();
}
}
void LdapModel::setPassword(const QString& data){
mPassword = data;
testPasswordField();
emit passwordChanged();
}
void LdapModel::testPasswordField(){
QString valid = "";
if( valid != mPasswordFieldError){
mPasswordFieldError = valid;
emit passwordFieldErrorChanged();
isValid();
}
}
void LdapModel::setBindDn(const QString& data){
mBindDn = data;
testBindDnField();
emit bindDnChanged();
}
void LdapModel::testBindDnField(){
QString valid;
if(mBindDn == "")
valid = "Bind DN must not be empty";
else
valid = "";
if( valid != mBindDnFieldError){
mBindDnFieldError = valid;
emit bindDnFieldErrorChanged();
isValid();
}
}
void LdapModel::setBaseObject(const QString& data){
mBaseObject = data;
testBaseObjectField();
emit baseObjectChanged();
}
void LdapModel::testBaseObjectField(){
QString valid;
if(mBaseObject == "")
valid = "Base Object must not be empty";
else
valid = "";
if( valid != mBaseObjectFieldError){
mBaseObjectFieldError = valid;
emit baseObjectFieldErrorChanged();
isValid();
}
}
void LdapModel::setFilter(const QString& data){
mFilter = data;
testFilterField();
emit filterChanged();
}
void LdapModel::testFilterField(){
QString valid = "";
if( valid != mFilterFieldError){
mFilterFieldError = valid;
emit filterFieldErrorChanged();
isValid();
}
}
void LdapModel::setNameAttributes(const QString& data){
mNameAttributes = data;
testNameAttributesField();
emit nameAttributesChanged();
}
void LdapModel::testNameAttributesField(){
QString valid = "";
if( valid != mNameAttributesFieldError){
mNameAttributesFieldError = valid;
emit nameAttributesFieldErrorChanged();
isValid();
}
}
void LdapModel::setSipAttributes(const QString& data){
mSipAttributes = data;
testSipAttributesField();
emit sipAttributesChanged();
}
void LdapModel::testSipAttributesField(){
QString valid = "";
if( valid != mSipAttributesFieldError){
mSipAttributesFieldError = valid;
emit sipAttributesFieldErrorChanged();
isValid();
}
}
void LdapModel::setSipScheme(const QString& data){
mSipScheme = data;
testSipSchemeField();
emit sipSchemeChanged();
}
void LdapModel::testSipSchemeField(){
QString valid = "";
if( valid != mSipSchemeFieldError){
mSipSchemeFieldError = valid;
emit sipSchemeFieldErrorChanged();
isValid();
}
}
void LdapModel::setSipDomain(const QString& data){
mSipDomain = data;
testSipDomainField();
emit sipDomainChanged();
}
void LdapModel::testSipDomainField(){
QString valid = "";
if( valid != mSipDomainFieldError){
mSipDomainFieldError = valid;
emit sipDomainFieldErrorChanged();
isValid();
}
}

View file

@ -0,0 +1,191 @@
/*
* Copyright (c) 2010-2020 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 <QAbstractListModel>
#include <QDateTime>
// =============================================================================
class CoreHandlers;
class LdapModel : public QObject {
Q_OBJECT
Q_PROPERTY(QVariantMap config READ getConfig WRITE setConfig NOTIFY configChanged)
Q_PROPERTY(bool isValid MEMBER mIsValid NOTIFY isValidChanged)
Q_PROPERTY(QString server MEMBER mServer WRITE setServer NOTIFY serverChanged)
Q_PROPERTY(QString serverFieldError MEMBER mServerFieldError NOTIFY serverFieldErrorChanged)
Q_PROPERTY(QString displayName MEMBER mDisplayName NOTIFY displayNameChanged)
Q_PROPERTY(bool useTls MEMBER mUseTls NOTIFY useTlsChanged)
Q_PROPERTY(bool useSal MEMBER mUseSal NOTIFY useSalChanged)
Q_PROPERTY(int maxResults MEMBER mMaxResults WRITE setMaxResults NOTIFY maxResultsChanged)
Q_PROPERTY(QString maxResultsFieldError MEMBER mMaxResultsFieldError NOTIFY maxResultsFieldErrorChanged)
Q_PROPERTY(QString password MEMBER mPassword WRITE setPassword NOTIFY passwordChanged)
Q_PROPERTY(QString passwordFieldError MEMBER mPasswordFieldError NOTIFY passwordFieldErrorChanged)
Q_PROPERTY(QString bindDn MEMBER mBindDn WRITE setBindDn NOTIFY bindDnChanged)
Q_PROPERTY(QString bindDnFieldError MEMBER mBindDnFieldError NOTIFY bindDnFieldErrorChanged)
Q_PROPERTY(QString baseObject MEMBER mBaseObject WRITE setBaseObject NOTIFY baseObjectChanged)
Q_PROPERTY(QString baseObjectFieldError MEMBER mBaseObjectFieldError NOTIFY baseObjectFieldErrorChanged)
Q_PROPERTY(QString filter MEMBER mFilter WRITE setFilter NOTIFY filterChanged)
Q_PROPERTY(QString filterFieldError MEMBER mFilterFieldError NOTIFY filterFieldErrorChanged)
Q_PROPERTY(QString nameAttributes MEMBER mNameAttributes WRITE setNameAttributes NOTIFY nameAttributesChanged)
Q_PROPERTY(QString nameAttributesFieldError MEMBER mNameAttributesFieldError NOTIFY nameAttributesFieldErrorChanged)
Q_PROPERTY(QString sipAttributes MEMBER mSipAttributes WRITE setSipAttributes NOTIFY sipAttributesChanged)
Q_PROPERTY(QString sipAttributesFieldError MEMBER mSipAttributesFieldError NOTIFY sipAttributesFieldErrorChanged)
Q_PROPERTY(QString sipScheme MEMBER mSipScheme WRITE setSipScheme NOTIFY sipSchemeChanged)
Q_PROPERTY(QString sipSchemeFieldError MEMBER mSipSchemeFieldError NOTIFY sipSchemeFieldErrorChanged)
Q_PROPERTY(QString sipDomain MEMBER mSipDomain WRITE setSipDomain NOTIFY sipDomainChanged)
Q_PROPERTY(QString sipDomainFieldError MEMBER mSipDomainFieldError NOTIFY sipDomainFieldErrorChanged)
Q_PROPERTY(bool debug MEMBER mDebug NOTIFY debugChanged)
Q_PROPERTY(int verifyServerCertificates MEMBER mVerifyServerCertificates NOTIFY verifyServerCertificatesChanged)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
public:
LdapModel (const int& id = 0,QObject *parent = nullptr);
QVariantMap mConfig;
bool mIsValid;
int mId; // "ldap_mId" from section name
QString mServer;
QString mServerFieldError;
void setServer(const QString& server);
void testServerField();
QString mDisplayName;
bool mUseSal;
bool mUseTls;
int mMaxResults;
QString mMaxResultsFieldError;
void setMaxResults(const int& data);
void testMaxResultsField();
QString mPassword;
QString mPasswordFieldError;
void setPassword(const QString& data);
void testPasswordField();
QString mBindDn;
QString mBindDnFieldError;
void setBindDn(const QString& data);
void testBindDnField();
QString mBaseObject;
QString mBaseObjectFieldError;
void setBaseObject(const QString& data);
void testBaseObjectField();
QString mFilter;
QString mFilterFieldError;
void setFilter(const QString& data);
void testFilterField();
QString mNameAttributes;
QString mNameAttributesFieldError;
void setNameAttributes(const QString& data);
void testNameAttributesField();
QString mSipAttributes;
QString mSipAttributesFieldError;
void setSipAttributes(const QString& data);
void testSipAttributesField();
QString mSipScheme;
QString mSipSchemeFieldError;
void setSipScheme(const QString& data);
void testSipSchemeField();
QString mSipDomain;
QString mSipDomainFieldError;
void setSipDomain(const QString& data);
void testSipDomainField();
bool mDebug;
int mVerifyServerCertificates;
bool isValid();
void init();// init by default value
Q_INVOKABLE void save();
void unsave();
bool load(const std::string& sectionName);
void set();
Q_INVOKABLE void unset();
QVariantMap getConfig();
void setConfig(const QVariantMap& config);
bool isEnabled();
void setEnabled(const bool& data);
signals:
void configChanged();
void isValidChanged();
void serverChanged();
void displayNameChanged();
void useTlsChanged();
void useSalChanged();
void isServerValidChanged();
void maxResultsChanged();
void passwordChanged();
void bindDnChanged();
void baseObjectChanged();
void filterChanged();
void nameAttributesChanged();
void sipAttributesChanged();
void sipSchemeChanged();
void sipDomainChanged();
void debugChanged();
void verifyServerCertificatesChanged();
void serverFieldErrorChanged();
void maxResultsFieldErrorChanged();
void passwordFieldErrorChanged();
void bindDnFieldErrorChanged();
void baseObjectFieldErrorChanged();
void filterFieldErrorChanged();
void nameAttributesFieldErrorChanged();
void sipAttributesFieldErrorChanged();
void sipSchemeFieldErrorChanged();
void sipDomainFieldErrorChanged();
void enabledChanged();
};
Q_DECLARE_METATYPE(LdapModel*);
#endif // LDAP_MODEL_H_

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2010-2020 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 "components/core/CoreManager.hpp"
#include "LdapModel.hpp"
#include "LdapListModel.hpp"
#include "LdapProxyModel.hpp"
// -----------------------------------------------------------------------------
LdapProxyModel::LdapProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(CoreManager::getInstance()->getLdapListModel());
sort(0);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
bool LdapProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return true;
}
bool LdapProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
const LdapModel* ldapA = sourceModel()->data(left).value<LdapModel*>();
const LdapModel* ldapB = sourceModel()->data(right).value<LdapModel*>();
return ldapA->mId <= ldapB->mId;
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2010-2020 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_MODEL_H_
#define LDAP_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
// =============================================================================
class LdapProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
LdapProxyModel (QObject *parent = Q_NULLPTR);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
};
#endif // LDAP_PROXY_MODEL_H_

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2021 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 "SearchHandler.hpp"
#include "linphone/api/c-search-result.h"
// =============================================================================
SearchHandler::SearchHandler(QObject * parent) : QObject(parent){
}
void SearchHandler::onSearchResultsReceived(const std::shared_ptr<linphone::MagicSearch> & magicSearch){
emit searchReceived(magicSearch->getLastSearch());
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2010-2020 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 SEARCH_HANDLER_H_
#define SEARCH_HANDLER_H_
#include <QObject>
#include <linphone++/linphone.hh>
#include <list>
// =============================================================================
class SearchHandler : public QObject, public linphone::MagicSearchListener{
Q_OBJECT
public:
SearchHandler(QObject * parent = nullptr);
virtual void onSearchResultsReceived(const std::shared_ptr<linphone::MagicSearch> & magicSearch);
signals:
void searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> );
};
Q_DECLARE_METATYPE(std::shared_ptr<linphone::SearchResult>);
#endif // SEARCH_HANDLER_H_

View file

@ -397,7 +397,7 @@ QVariantList AccountSettingsModel::getAccounts () const {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
QVariantList accounts;
{
if(CoreManager::getInstance()->getSettingsModel()->getShowLocalSipAccount()) {
QVariantMap account;
account["sipAddress"] = Utils::coreStringToAppString(core->createPrimaryContactParsed()->asStringUriOnly());
account["fullSipAddress"] = QString::fromStdString(core->createPrimaryContactParsed()->asString());

View file

@ -1188,6 +1188,20 @@ void SettingsModel::setExitOnClose (bool value) {
emit exitOnCloseChanged(value);
}
// -----------------------------------------------------------------------------
bool SettingsModel::getShowLocalSipAccount()const{
return !!mConfig->getInt(UiSection, "show_local_sip_account", 1);
}
bool SettingsModel::getShowStartChatButton ()const{
return !!mConfig->getInt(UiSection, "show_start_chat_button", 1);
}
bool SettingsModel::getShowStartVideoCallButton ()const{
return !!mConfig->getInt(UiSection, "show_start_video_button", 1);
}
// =============================================================================
// Advanced.
// =============================================================================

View file

@ -170,6 +170,10 @@ class SettingsModel : public QObject {
Q_PROPERTY(bool exitOnClose READ getExitOnClose WRITE setExitOnClose NOTIFY exitOnCloseChanged)
Q_PROPERTY(bool showLocalSipAccount READ getShowLocalSipAccount CONSTANT)
Q_PROPERTY(bool showStartChat READ getShowStartChatButton CONSTANT)
Q_PROPERTY(bool showStartVideoCallButton READ getShowStartVideoCallButton CONSTANT)
// Advanced. -----------------------------------------------------------------
Q_PROPERTY(QString logsFolder READ getLogsFolder WRITE setLogsFolder NOTIFY logsFolderChanged)
@ -426,6 +430,10 @@ public:
bool getExitOnClose () const;
void setExitOnClose (bool value);
bool getShowLocalSipAccount () const;
bool getShowStartChatButton () const;
bool getShowStartVideoCallButton () const;
// Advanced. ---------------------------------------------------------------------------

View file

@ -0,0 +1,151 @@
/*
* Copyright (c) 2010-2020 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 <QDateTime>
#include <QElapsedTimer>
#include <QUrl>
#include <QtDebug>
#include "components/call/CallModel.hpp"
#include "components/chat/ChatModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
#include "components/core/CoreManager.hpp"
#include "components/history/HistoryModel.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "utils/LinphoneUtils.hpp"
#include "utils/Utils.hpp"
#include "SearchSipAddressesModel.hpp"
// =============================================================================
using namespace std;
// -----------------------------------------------------------------------------
/*
static inline QVariantMap buildVariantMap (const SearchSipAddressesModel::SipAddressEntry &sipAddressEntry) {
return QVariantMap{
{ "sipAddress", sipAddressEntry.sipAddress },
{ "contact", QVariant::fromValue(sipAddressEntry.contact) },
{ "presenceStatus", sipAddressEntry.presenceStatus },
{ "__localToConferenceEntry", QVariant::fromValue(&sipAddressEntry.localAddressToConferenceEntry) }
};
}
*/
SearchSipAddressesModel::SearchSipAddressesModel (QObject *parent) : QAbstractListModel(parent) {
mMagicSearch = CoreManager::getInstance()->getCore()->createMagicSearch();
mSearch = std::make_shared<SearchHandler>(this);
QObject::connect(mSearch.get(), SIGNAL(searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> )), this, SLOT(searchReceived(std::list<std::shared_ptr<linphone::SearchResult>>)));
mMagicSearch->addListener(mSearch);
}
SearchSipAddressesModel::~SearchSipAddressesModel(){
mMagicSearch->removeListener(mSearch);
}
// -----------------------------------------------------------------------------
int SearchSipAddressesModel::rowCount (const QModelIndex &) const {
return mAddresses.count()-1;
}
QHash<int, QByteArray> SearchSipAddressesModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$sipAddress";
return roles;
}
QVariant SearchSipAddressesModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mAddresses.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariantMap{{"sipAddress", mAddresses[row]}};
return QVariant();
}
// -----------------------------------------------------------------------------
bool SearchSipAddressesModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
}
bool SearchSipAddressesModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mAddresses.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mAddresses.removeAt(row);
endRemoveRows();
return true;
}
static std::list<std::pair<std::shared_ptr<linphone::MagicSearch>, std::shared_ptr<SearchHandler> > > searches;
class DeleteMagic{
public:
std::shared_ptr<linphone::MagicSearch> magic;
std::shared_ptr<SearchHandler> search;
};
void SearchSipAddressesModel::setFilter(const QString& filter){
mMagicSearch->getContactListFromFilterAsync(filter.toStdString(),"");
//searchReceived(mMagicSearch->getContactListFromFilter(filter.toStdString(),"")); // Just to show how to use sync method
}
void SearchSipAddressesModel::searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> results){
beginResetModel();
mAddresses.clear();
for(auto it = results.begin() ; it != results.end() ; ++it){
if((*it)->getFriend()){
//QString username = QString::fromStdString((*it)->getFriend()->getName());
//auto f = (*it)->getFriend();
//auto vcard = f->getVcard();
//if(vcard)
// qDebug() << QString::fromStdString(vcard->asVcard4String());
mAddresses << QString::fromStdString((*it)->getFriend()->getAddress()->asString());
//qDebug() << username << " " << QString::fromStdString((*it)->getFriend()->getAddress()->getDisplayName());
}else{
//QString username = QString::fromStdString((*it)->getAddress()->getDisplayName());
mAddresses << QString::fromStdString((*it)->getAddress()->asString());
//qDebug() << username;
}
}
//invalidate();
endResetModel();
/*
mMagicSearch->removeListener(mSearch);
mMagicSearch = nullptr;
mSearch = nullptr;*/
}

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2010-2020 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 SEARCH_SIP_ADDRESSES_MODEL_H_
#define SEARCH_SIP_ADDRESSES_MODEL_H_
#include <QAbstractListModel>
#include <QDateTime>
#include <list>
#include <linphone++/linphone.hh>
#include "../search/SearchHandler.hpp"
// =============================================================================
class SearchSipAddressesModel : public QAbstractListModel {
Q_OBJECT;
public:
SearchSipAddressesModel (QObject *parent = Q_NULLPTR);
~SearchSipAddressesModel();
int rowCount (const QModelIndex &index = QModelIndex()) const override;
QHash<int, QByteArray> roleNames () const override;
QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE void setFilter (const QString &pattern);
QStringList mAddresses;
std::shared_ptr<linphone::MagicSearch> mMagicSearch;
std::shared_ptr<SearchHandler> mSearch;
public slots:
void searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> results);
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
};
Q_DECLARE_METATYPE(SearchSipAddressesModel *);
#endif // SIP_ADDRESSES_MODEL_H_

View file

@ -0,0 +1,130 @@
/*
* Copyright (c) 2010-2020 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 "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/core/CoreManager.hpp"
#include "SearchSipAddressesModel.hpp"
#include "SearchSipAddressesProxyModel.hpp"
// =============================================================================
namespace {
constexpr int WeightPos0 = 5;
constexpr int WeightPos1 = 4;
constexpr int WeightPos2 = 3;
constexpr int WeightPos3 = 2;
constexpr int WeightPosOther = 1;
}
const QRegExp SearchSipAddressesProxyModel::SearchSeparators("^[^_.-;@ ][_.-;@ ]");
// -----------------------------------------------------------------------------
SearchSipAddressesProxyModel::SearchSipAddressesProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(CoreManager::getInstance()->getSipAddressesModel());
sort(0);
}
// -----------------------------------------------------------------------------
void SearchSipAddressesProxyModel::setFilter (const QString &pattern) {
mFilter = pattern;
invalidate();
}
// -----------------------------------------------------------------------------
bool SearchSipAddressesProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return computeEntryWeight(index.data().toMap()) > 0;
}
bool SearchSipAddressesProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
const QVariantMap mapA = sourceModel()->data(left).toMap();
const QVariantMap mapB = sourceModel()->data(right).toMap();
const QString sipAddressA = mapA["sipAddress"].toString();
const QString sipAddressB = mapB["sipAddress"].toString();
// TODO: Use a cache, do not compute the same value as `filterAcceptsRow`.
int weightA = computeEntryWeight(mapA);
int weightB = computeEntryWeight(mapB);
// 1. Not the same weight.
if (weightA != weightB)
return weightA > weightB;
const ContactModel *contactA = mapA.value("contact").value<ContactModel *>();
const ContactModel *contactB = mapB.value("contact").value<ContactModel *>();
// 2. No contacts.
if (!contactA && !contactB)
return sipAddressA <= sipAddressB;
// 3. No contact for a or b.
if (!contactA || !contactB)
return !!contactA;
// 4. Same contact (address).
if (contactA == contactB)
return sipAddressA <= sipAddressB;
// 5. Not the same contact name.
int diff = contactA->mLinphoneFriend->getName().compare(contactB->mLinphoneFriend->getName());
if (diff)
return diff <= 0;
// 6. Same contact name, so compare sip addresses.
return sipAddressA <= sipAddressB;
}
int SearchSipAddressesProxyModel::computeEntryWeight (const QVariantMap &entry) const {
int weight = computeStringWeight(entry["sipAddress"].toString().mid(4));
const ContactModel *contact = entry.value("contact").value<ContactModel *>();
if (contact)
weight += computeStringWeight(contact->getVcardModel()->getUsername());
return weight;
}
int SearchSipAddressesProxyModel::computeStringWeight (const QString &string) const {
int index = -1;
int offset = -1;
while ((index = string.indexOf(mFilter, index + 1, Qt::CaseInsensitive)) != -1) {
int tmpOffset = index - string.lastIndexOf(SearchSeparators, index) - 1;
if ((tmpOffset != -1 && tmpOffset < offset) || offset == -1)
if ((offset = tmpOffset) == 0) break;
}
switch (offset) {
case -1: return 0;
case 0: return WeightPos0;
case 1: return WeightPos1;
case 2: return WeightPos2;
case 3: return WeightPos3;
default: break;
}
return WeightPosOther;
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2010-2020 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 SEARCH_SIP_ADDRESSES_PROXY_MODEL_H_
#define SEARCH_SIP_ADDRESSES_PROXY_MODEL_H_
#include <QSortFilterProxyModel>
// =============================================================================
class SearchSipAddressesProxyModel : public QSortFilterProxyModel {
Q_OBJECT;
public:
SearchSipAddressesProxyModel (QObject *parent = Q_NULLPTR);
Q_INVOKABLE void setFilter (const QString &pattern);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
private:
int computeEntryWeight (const QVariantMap &entry) const;
int computeStringWeight (const QString &string) const;
QString mFilter;
static const QRegExp SearchSeparators;
};
#endif // SIP_ADDRESSES_PROXY_MODEL_H_

View file

@ -92,4 +92,22 @@ Controls.TextField {
iconSize: parent.contentHeight
visible: !parent.text
}
bottomPadding: (statusItem.visible?statusItem.height:0)
TextEdit{
id:statusItem
selectByMouse: true
readOnly:true
color: TextFieldStyle.background.border.color.error
width:parent.width
anchors.bottom:parent.bottom
anchors.right:parent.right
anchors.rightMargin:10 + toolsContainer.width
horizontalAlignment:Text.AlignRight
font {
italic: true
pointSize: TextFieldStyle.text.pointSize
}
visible:error!= ''
text:error
}
}

View file

@ -2,6 +2,7 @@ import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common.Styles 1.0
import Common 1.0
// =============================================================================
@ -9,6 +10,8 @@ Column {
property alias title: title.text
property bool dealWithErrors: false
property int orientation: Qt.Horizontal
property bool addButton : false
signal addButtonClicked;
// ---------------------------------------------------------------------------
@ -21,14 +24,26 @@ Column {
visible: parent.title.length > 0
width: parent.width
Text {
id: title
color: FormStyle.header.title.color
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
Row{
spacing:10
Text {
id: title
anchors.verticalCenter: parent.verticalCenter
color: FormStyle.header.title.color
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
}
ActionButton {
visible:addButton
anchors.verticalCenter: parent.verticalCenter
icon: 'add'
iconSize:38
scale:0.8
onClicked:addButtonClicked()
}
}
Rectangle {

View file

@ -5,7 +5,7 @@ import Common.Styles 1.0
// =============================================================================
Row {
readonly property double maxItemWidth: {
property double maxItemWidth: {
var n = children.length
var curWidth = width / n - (n - 1) * spacing
var maxWidth = orientation === Qt.Horizontal

View file

@ -1,12 +1,12 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Controls 2.2 as Controls
import Common 1.0
import Common.Styles 1.0
// =============================================================================
Switch {
Controls.Switch {
id: control
// ---------------------------------------------------------------------------

View file

@ -47,6 +47,8 @@ TextField 1.0 Form/Fields/TextField.qml
Form 1.0 Form/Placements/Form.qml
FormEmptyLine 1.0 Form/Placements/FormEmptyLine.qml
FormGroup 1.0 Form/Placements/FormGroup.qml
FormHGroup 1.0 Form/Placements/FormHGroup.qml
FormVGroup 1.0 Form/Placements/FormVGroup.qml
FormLine 1.0 Form/Placements/FormLine.qml
FormTable 1.0 Form/Placements/FormTable.qml
FormTableEntry 1.0 Form/Placements/FormTableEntry.qml

View file

@ -33,11 +33,11 @@ Notification {
Contact {
Layout.fillWidth: true
entry: {
var call = notification.call
return SipAddressesModel.getSipAddressObserver(call ? call.fullPeerAddress : '', call ? call.fullLocalAddress : '')
}
property var peerAddress: notification.call ? notification.call.fullPeerAddress : ''
onPeerAddressChanged: {
entry=SipAddressesModel.getSipAddressObserver(peerAddress, notification.call ? notification.call.fullLocalAddress : '')
}
entry: SipAddressesModel.getSipAddressObserver(peerAddress, notification.call ? notification.call.fullLocalAddress : '')
}
// ---------------------------------------------------------------------

View file

@ -46,7 +46,7 @@ SearchBox {
searchBox.closeMenu()
searchBox.launchVideoCall(entry.sipAddress)
},
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled && SettingsModel.showStartVideoCallButton
}, {
icon: 'call',
handler: function (entry) {
@ -55,7 +55,7 @@ SearchBox {
},
visible: SettingsModel.outgoingCallsEnabled
}, {
icon: SettingsModel.chatEnabled ? 'chat' : 'history',
icon: SettingsModel.chatEnabled && SettingsModel.showStartChatButton ? 'chat' : 'history',
handler: function (entry) {
searchBox.closeMenu()
searchBox.launchChat(entry.sipAddress)
@ -71,7 +71,7 @@ SearchBox {
genSipAddress: searchBox.filter
model: SipAddressesProxyModel {}
model: SearchSipAddressesModel {}
onEntryClicked: {
searchBox.closeMenu()

View file

@ -64,7 +64,7 @@ DialogPlus {
CallsListModel.launchVideoCall(entry.sipAddress)
exit(1)
},
visible: SettingsModel.videoSupported
visible: SettingsModel.videoSupported && SettingsModel.showStartVideoCallButton
}, {
icon: 'call',
handler: function (entry) {
@ -75,7 +75,7 @@ DialogPlus {
genSipAddress: filter.text
model: SipAddressesProxyModel {
model: SearchSipAddressesModel {
id: sipAddressesModel
}

View file

@ -88,7 +88,7 @@ DialogPlus {
genSipAddress: filter.text
model: SipAddressesProxyModel {
model: SearchSipAddressesModel {
id: sipAddressesModel
}

View file

@ -420,7 +420,7 @@ Rectangle {
}
ActionButton {
icon: SettingsModel.chatEnabled ? 'chat' : 'history'
icon: SettingsModel.chatEnabled && SettingsModel.showStartChatButton ? 'chat' : 'history'
onClicked: {
if (window.chatIsOpened) {

View file

@ -132,7 +132,7 @@ ColumnLayout {
ActionButton {
icon: 'video_call'
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled && SettingsModel.showStartVideoCallButton
onClicked: actions.itemAt(0).open()
}
@ -145,7 +145,7 @@ ColumnLayout {
}
ActionButton {
icon: SettingsModel.chatEnabled ? 'chat' : 'history'
icon: SettingsModel.chatEnabled && SettingsModel.showStartChatButton ? 'chat' : 'history'
onClicked: actions.itemAt(2).open()
}
}

View file

@ -78,7 +78,7 @@ ColumnLayout {
ActionButton {
icon: 'video_call'
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled && SettingsModel.showStartVideoCallButton
onClicked: CallsListModel.launchVideoCall(conversation.peerAddress)
}

View file

@ -81,7 +81,7 @@ ColumnLayout {
ActionButton {
icon: 'video_call'
visible: peerAddress && SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled
visible: peerAddress && SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled && SettingsModel.showStartVideoCallButton
onClicked: CallsListModel.launchVideoCall(historyView.peerAddress)
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2010-2020 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/>.
*/
// =============================================================================
// `SettingsSipAccounts.qml` Logic.
// =============================================================================
.import Linphone 1.0 as Linphone
.import 'qrc:/ui/scripts/Utils/utils.js' as Utils
// =============================================================================
var proxyConfig
function initForm (ldap) {
/*
var AccountSettingsModel = Linphone.AccountSettingsModel
proxyConfig = account
? account.proxyConfig
: AccountSettingsModel.createProxyConfig()
var config = AccountSettingsModel.getProxyConfigDescription(proxyConfig)
sipAddress.text = config.sipAddress
serverAddress.text = config.serverAddress
registrationDuration.text = config.registrationDuration
var currentTransport = config.transport.toUpperCase()
transport.currentIndex = Number(
Utils.findIndex(transport.model, function (value) {
return value === currentTransport
})
)
route.text = config.route
contactParams.text = config.contactParams
avpfInterval.text = config.avpfInterval
registerEnabled.checked = config.registerEnabled
publishPresence.checked = config.publishPresence
avpfEnabled.checked = config.avpfEnabled
iceEnabled.checked = config.iceEnabled
turnEnabled.checked = config.turnEnabled
stunServer.text = config.stunServer
turnPassword.text = config.turnPassword
turnUser.text = config.turnUser
if (account) {
dialog._sipAddressOk = true
dialog._serverAddressOk = true
}
dialog._routeOk = true
*/
}
function formIsValid () {
//return dialog._sipAddressOk && dialog._serverAddressOk && dialog._routeOk
}
// -----------------------------------------------------------------------------
function validProxyConfig () {
/*
if (Linphone.AccountSettingsModel.addOrUpdateProxyConfig(proxyConfig, {
sipAddress: sipAddress.text,
serverAddress: serverAddress.text,
registrationDuration: registrationDuration.text,
transport: transport.currentText,
route: route.text,
contactParams: contactParams.text,
avpfInterval: avpfInterval.text,
registerEnabled: registerEnabled.checked,
publishPresence: publishPresence.checked,
avpfEnabled: avpfEnabled.checked,
iceEnabled: iceEnabled.checked,
turnEnabled: turnEnabled.checked,
stunServer: stunServer.text,
turnUser: turnUser.text,
turnPassword: turnPassword.text
})) {
dialog.exit(1)
} else {
// TODO: Display errors on the form (if necessary).
}
*/
}
// -----------------------------------------------------------------------------
function handleRouteChanged (route) {
// dialog._routeOk = route.length === 0 || Linphone.SipAddressesModel.addressIsValid(route)
}
function handleServerAddressChanged (address) {
/*
if (address.length === 0) {
dialog._serverAddressOk = false
return
}
var newTransport = Linphone.SipAddressesModel.getTransportFromSipAddress(address)
if (newTransport.length > 0) {
transport.currentIndex = Utils.findIndex(transport.model, function (value) {
return value === newTransport
})
dialog._serverAddressOk = true
} else {
dialog._serverAddressOk = false
}*/
}
function handleSipAddressChanged (address) {
/*
dialog._sipAddressOk = address.length > 0 &&
Linphone.SipAddressesModel.sipAddressIsValid(address)*/
}
function handleTransportChanged (transport) {
/*
var newServerAddress = Linphone.SipAddressesModel.addTransportToSipAddress(serverAddress.text, transport)
if (newServerAddress.length > 0) {
serverAddress.text = newServerAddress
dialog._serverAddressOk = true
} else {
dialog._serverAddressOk = false
}*/
}
// -----------------------------------------------------------------------------

View file

@ -0,0 +1,332 @@
import QtQuick 2.7
import Common 1.0
import Linphone 1.0
import App.Styles 1.0
import 'SettingsLdapEdit.js' as Logic
// =============================================================================
DialogPlus {
id: dialog
property LdapModel ldapData
buttons: [
TextButtonA {
text: qsTr('cancel')
onClicked: {
ldapData.unset()
exit(0)}
},
TextButtonB {
enabled: ldapData.isValid
text: qsTr('confirm')
onClicked: {ldapData.save()
exit(1)
}
}
]
centeredButtons: true
height: SettingsSipAccountsEditStyle.height
width: SettingsSipAccountsEditStyle.width
// ---------------------------------------------------------------------------
//Component.onCompleted: Logic.initForm(ldapData)
// ---------------------------------------------------------------------------
TabContainer {
anchors.fill: parent
Column {
width: parent.width
Form {
title: ''
width: parent.width
FormLine {
FormGroup {
label: 'Display Name'
TextField {
id:displayName
placeholderText : (serverUrl.text?serverUrl.text:serverUrl.placeholderText)
text:ldapData.displayName
onTextChanged: ldapData.displayName = text
Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()
TooltipArea{
text : 'LDAP Server. eg: ldap:/// for a localhost server or ldap://ldap.example.org/'
}
}
}
}
}
Form {
title: 'Connection'
width: parent.width
FormLine {
FormGroup {
label: 'Server URL *'
TextField {
id:serverUrl
placeholderText :"Server"
text:ldapData.server
onTextChanged: ldapData.server = text
Keys.onReturnPressed: nextItemInFocusChain().forceActiveFocus()
error : ldapData.serverFieldError
TooltipArea{
text : 'LDAP Server. eg: ldap:/// for a localhost server or ldap://ldap.example.org/'
}
}
}
}
FormLine {
FormGroup {
label: 'Bind DN *'
TextField {
id: bindDn
placeholderText :"Bind DN"
text:ldapData.bindDn
error : ldapData.bindDnFieldError
onTextChanged: ldapData.bindDn= text
TooltipArea{
text : 'The bindDN DN is the credential that is used to authenticate against an LDAP.\n eg: cn=ausername,ou=people,dc=bc,dc=com'
}
}
}
}
FormLine {
FormGroup {
label: 'Password'
PasswordField {
id:password
text:ldapData.password
error : ldapData.passwordFieldError
onTextChanged: ldapData.password = text
placeholderText :"Password"
}
}
}
FormLine {
id:useRow
FormGroup {
label: 'Use TLS'
Switch {
id: useTls
anchors.verticalCenter: parent.verticalCenter
checked: ldapData.useTls
onClicked: {
ldapData.useTls = !checked
}
TooltipArea{
tooltipParent:useRow
text : 'Encrypt transactions by LDAP over TLS(StartTLS). You must use \'ldap\' scheme. \'ldaps\' for LDAP over SSL is non-standardized and deprecated.\nStartTLS in an extension to the LDAP protocol which uses the TLS protocol to encrypt communication. \nIt works by establishing a normal - i.e. unsecured - connection with the LDAP server before a handshake negotiation between the server and the web services is carried out. Here, the server sends its certificate to prove its identity before the secure connection is established.'
}
}
}
FormGroup {
label: 'Use Sal'
Switch {
id: useSal
anchors.verticalCenter: parent.verticalCenter
checked: ldapData.useSal
onClicked: {
ldapData.useSal = !checked
}
TooltipArea{
tooltipParent:useRow
text : 'The dns resolution is done by Linphone using Sal. It will pass an IP to LDAP. By doing that, the TLS negociation could not check the hostname. You may deactivate the verifications if wanted to force the connection.'
}
}
}
}
FormLine{
id:useSalRow
FormGroup {
label: 'Verify Certificates on TLS'
ComboBox {
id:verifyServerCertificates
currentIndex: ldapData.verifyServerCertificates+1
model: ["Auto", "Off", "On"]
width: parent.width
onActivated: ldapData.verifyServerCertificates = index-1
TooltipArea{
text : 'Specify whether the tls server certificate must be verified when connecting to a LDAP server.'
}
}
}
}
}
// -----------------------------------------------------------------------
// NAT and Firewall.
// -----------------------------------------------------------------------
Form {
title: 'Search'
width: parent.width
FormLine {
FormGroup {
label: 'Base Object *'
TextField {
id:baseObject
placeholderText :"Base Object"
text:ldapData.baseObject
error : ldapData.baseObjectFieldError
onTextChanged: ldapData.baseObject = text
TooltipArea{
text : 'BaseObject is a specification for LDAP Search Scopes that specifies that the Search Request should only be performed against the entry specified as the search base DN.\n\nNo entries below it will be considered.'
}
}
}
}
FormLine {
FormGroup {
label: 'Filter'
TextField {
id:filter
text:ldapData.filter
error : ldapData.filterFieldError
onTextChanged: ldapData.filter = text
placeholderText :"(sn=%s)"
TooltipArea{
text : 'The search is base on this filter to search friends. Default value : (sn=%s)'
}
}
}
}
FormLine {
FormGroup {
label: 'Max Results'
NumericField {
id:maxResults
text:ldapData.maxResults
error : ldapData.maxResultsFieldError
onTextChanged: ldapData.maxResults = text
TooltipArea{
text : 'The max results when requesting searches'
}
}
}
}
}
// -----------------------------------------------------------------------
// Parsing
// -----------------------------------------------------------------------
Form {
title: 'Parsing'
width: parent.width
FormLine {
FormGroup {
label: 'Name Attributes'
TextField {
id:nameAttributes
placeholderText :'sn'
text:ldapData.nameAttributes
error : ldapData.nameAttributesFieldError
onTextChanged: ldapData.nameAttributes = text
TooltipArea{
text : 'Check these attributes To build Name Friend, separated by a comma and the first is the highest priority. The default value is: sn'
}
}
}
}
FormLine {
FormGroup {
label: 'Sip Attributes'
TextField {
id:sipAttributes
placeholderText :'mobile,telephoneNumber,homePhone,sn'
text:ldapData.sipAttributes
error : ldapData.sipAttributesFieldError
onTextChanged: ldapData.sipAttributes = text
TooltipArea{
text : 'Check these attributes to build the SIP username in address of Friend. Attributes are separated by a comma and the first is the highest priority. The default value is: mobile,telephoneNumber,homePhone,sn'
}
}
}
}
FormLine {
FormGroup {
label: 'Scheme'
TextField {
id:scheme
placeholderText :'sip'
text:ldapData.sipScheme
error : ldapData.sipSchemeFieldError
onTextChanged: ldapData.sipScheme = text
TooltipArea{
text : 'Add the scheme to the sip address(scheme:username@domain). The default value is sip'
}
}
}
}
FormLine {
FormGroup {
label: 'Domain'
TextField {
id:domain
placeholderText :'sip.linphone.org'
text:ldapData.sipDomain
error : ldapData.sipDomainFieldError
onTextChanged: ldapData.sipDomain = text
TooltipArea{
text : 'Add the domain to the sip address(scheme:username@domain). The default value is sip.linphone.org'
}
}
}
}
}
// -----------------------------------------------------------------------
// Misc
// -----------------------------------------------------------------------
Form {
title: 'Misc'
width: parent.width
FormLine {
id:miscLine
FormGroup {
label: 'Debug'
Switch {
id: debugMode
anchors.verticalCenter: parent.verticalCenter
checked: ldapData.debug
onClicked: {
ldapData.debug = !checked
}
TooltipArea{
tooltipParent:miscLine
text : 'Get verbose logs in Linphone log file when doing transactions (useful to debug TLS connections)'
}
}
}
}
}
}
}
}

View file

@ -27,6 +27,12 @@
// =============================================================================
function editLdap (ldap) {
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/SettingsLdapEdit.qml'), {
ldapData: ldap
})
}
function cleanLogs () {
window.attachVirtualWindow(Utils.buildDialogUri('ConfirmDialog'), {
descriptionText: qsTr('cleanLogsDescription'),

View file

@ -16,7 +16,9 @@ import 'SettingsAdvanced.js' as Logic
// =============================================================================
TabContainer {
Column {
color: "#00000000"
Column {
id: column
spacing: SettingsWindowStyle.forms.spacing
width: parent.width
@ -97,7 +99,22 @@ TabContainer {
}
}
onVisibleChanged: sendLogsBlock.setText('')
// -------------------------------------------------------------------------
// LDAP
// -------------------------------------------------------------------------
Form {
title: 'LDAP'
width: parent.width
addButton:true
onAddButtonClicked:ldapSection.add()
SettingsLdap{
id:ldapSection
width: parent.width
}
}
// -------------------------------------------------------------------------
// ADDRESS BOOK
// -------------------------------------------------------------------------
@ -173,7 +190,6 @@ TabContainer {
Component{
id: textComponent
Text {
id: text
color: FormTableStyle.entry.text.color
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
@ -300,7 +316,7 @@ TabContainer {
Form {
title: qsTr('developerSettingsTitle')
visible: SettingsModel.developerSettingsEnabled
// visible: SettingsModel.developerSettingsEnabled
width: parent.width
FormLine {
@ -317,3 +333,9 @@ TabContainer {
}
}
}
/*##^##
Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

View file

@ -0,0 +1,77 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import App.Styles 1.0
import Linphone.Styles 1.0
import Common.Styles 1.0
import 'SettingsAdvanced.js' as Logic
// =============================================================================
Column {
id: mainColumn
// ---------------------------------------------------------------------------
function add(){
LdapListModel.add()
}
spacing: FormStyle.spacing
// ---------------------------------------------------------------------------
Repeater{
id: ldapList
model:LdapProxyModel{id:ldapProxy}
delegate:Item{
id: swipeView
anchors.left: parent.left
anchors.right: parent.right
clip:true
height:summaryRowItem.height
Item{
id: summaryRow
anchors.fill:parent
Row{
id:summaryRowItem
anchors.horizontalCenter: parent.horizontalCenter
spacing:20
ActionButton {
id:removeldap
anchors.verticalCenter: parent.verticalCenter
icon: 'cancel'
iconSize:CallsStyle.entry.iconActionSize
scale:0.8
onClicked:LdapListModel.remove(modelData)
}
Text {
id: summaryTitle
color: FormStyle.header.title.color
text: (modelData.displayName?modelData.displayName:(modelData.server?modelData.server:'New server'))
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
anchors.verticalCenter: parent.verticalCenter
MouseArea{
anchors.fill:parent
onClicked:Logic.editLdap(modelData)
}
}
Switch {
id: ldapActivation
anchors.verticalCenter: parent.verticalCenter
checked: modelData.enabled
onClicked: {
modelData.enabled = !checked
}
}
}
}
}
}
}

View file

@ -0,0 +1,421 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
//import QtQuick.Controls 2.15 // SwipeView : Qt 5.7
import QtQuick.Controls 1.4 // TabView
import Common 1.0
import Linphone 1.0
import App.Styles 1.0
import Linphone.Styles 1.0
import Common.Styles 1.0
// =============================================================================
//Qt *View override childs geometry. Do not use them
Item{
id: swipeView
anchors.left: parent.left
anchors.right: parent.right
property LdapModel ldapData
property int currentIndex: ldapData.isValid?0:1
clip:true
Component.onCompleted:updateHeight()
onCurrentIndexChanged:updateHeight()
function updateHeight(){
if( currentIndex==0)
swipeView.height=summaryRowItem.height
else if( currentIndex==1)
swipeView.height=mainColumn.height
}
Item{
id: summaryRow
anchors.fill:parent
visible:currentIndex == 0
Row{
id:summaryRowItem
anchors.horizontalCenter: parent.horizontalCenter
spacing:10
ActionButton {
id:removeldap
anchors.verticalCenter: parent.verticalCenter
icon: 'cancel'
iconSize:CallsStyle.entry.iconActionSize
scale:0.8
}
Text {
id: summaryTitle
color: FormStyle.header.title.color
text: serverUrl.text?serverUrl.text:'New server'
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
anchors.verticalCenter: parent.verticalCenter
MouseArea{
anchors.fill:parent
onClicked:swipeView.currentIndex = 1
}
}
Switch {
id: ldapActivation
anchors.verticalCenter: parent.verticalCenter
checked: false
onClicked: {
checked = !checked
}
}
}
}
Item {
id: page2
anchors.fill:parent
visible:currentIndex == 1
Column {
id: mainColumn
property bool dealWithErrors: false
property int orientation: Qt.Horizontal
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
height:centerRow.height+titleRow.height+spacing*2
// ---------------------------------------------------------------------------
spacing: FormStyle.spacing
// ---------------------------------------------------------------------------
Column{
id:titleRow
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
spacing: FormStyle.header.spacing
Text {
id: title
text:"LDAP Server settings :"+serverUrl.text
color: FormStyle.header.title.color
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
}
Rectangle {
anchors.left:parent.left
anchors.right:parent.right
color: FormStyle.header.separator.color
}
}
Item{
id: centerRow
anchors.left:parent.left
anchors.right:parent.right
transformOrigin: Item.Center
layer.wrapMode: ShaderEffectSource.ClampToEdge
height:detailsRow.height
ActionButton {
id:back
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 0
icon: 'edit'
iconSize:CallsStyle.entry.iconActionSize
onClicked:swipeView.currentIndex = 0
}
RowLayout{// Details row have its size from children
id:detailsRow
anchors.left: back.right
anchors.right: deleteLdap.left
anchors.rightMargin: 10
anchors.leftMargin: 10
ColumnLayout{
Layout.fillHeight: true
Layout.fillWidth:true
TextField {
id:serverUrl
Layout.fillWidth: true
placeholderText :"Server"
TooltipArea{
text : 'LDAP Server. eg: ldap:/// for a localhost server or ldap://ldap.example.org/'
}
}
TextField {
Layout.fillWidth: true
placeholderText :"Bind DN"
TooltipArea{
text : 'The bindDN DN is the credential that is used to authenticate against an LDAP.\n eg: cn=ausername,ou=people,dc=bc,dc=com'
}
}
PasswordField {
Layout.fillWidth: true
placeholderText :"Password"
}
Switch {
id: useTlsLdap
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 0
checked: false
onClicked: {
checked = !checked
}
}
}
ColumnLayout{
Layout.fillHeight: true
Layout.fillWidth:true
TextField {
Layout.fillWidth: true
placeholderText :"Base Object"
TooltipArea{
text : ''
}
}
TextField {
text: "Filter"
Layout.fillWidth: true
placeholderText :"Filter"
TooltipArea{
text : 'The search is base on this filter to search friends. Default value : (sn=%s)'
}
}
NumericField {
text: "MaxResults"
Layout.fillWidth: true
TooltipArea{
text : 'The max results when requesting searches'
}
}
}
ColumnLayout{
Layout.fillHeight: true
Layout.fillWidth:true
TextField {
Layout.fillWidth: true
placeholderText :"Names Attributes"
TooltipArea{
text : 'Check these attributes To build Name Friend, separated by a comma and the first is the highest priority. The default value is: sn'
}
}
TextField {
Layout.fillWidth: true
placeholderText :"Sip Attributes"
TooltipArea{
text : 'Check these attributes To build the SIP username in address of Friend, separated by a comma and the first is the highest priority. The default value is: mobile,telephoneNumber,homePhone,sn'
}
}
TextField {
Layout.fillWidth: true
placeholderText :"Scheme"
TooltipArea{
text : 'Add the scheme to the sip address(scheme:username@domain). The default value is sip'
}
}
TextField {
Layout.fillWidth: true
placeholderText :"Domain"
TooltipArea{
text : 'Add the domain to the sip address(scheme:username@domain). The default value is the ldap server url'
}
}
}
}
Switch {
id: deleteLdap
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 0
checked: false
onClicked: {
checked = !checked
}
}
}
}
}
/*
Column{
id:summaryRow
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
spacing: FormStyle.header.spacing
//visible: parent.title.length > 0
height:summaryTitle.height
Text {
id: summaryTitle
color: FormStyle.header.title.color
text: "Summary of "// +serverUrl.text
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
}
MouseArea{
onClicked: swipeView.currentIndex = 2
anchors.fill:parent
Rectangle{
anchors.fill:parent
color:"red"
}
}
}
Column {
id: mainColumn
property alias title: title.text
property bool dealWithErrors: false
property int orientation: Qt.Horizontal
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
height:centerRow.height+titleRow.height+spacing*2
// ---------------------------------------------------------------------------
spacing: FormStyle.spacing
// ---------------------------------------------------------------------------
Column{
id:titleRow
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
spacing: FormStyle.header.spacing
//visible: parent.title.length > 0
Text {
id: title
text:"LDAP Server :"+serverUrl.text
color: FormStyle.header.title.color
font {
bold: true
pointSize: FormStyle.header.title.pointSize
}
}
Rectangle {
anchors.left:parent.left
anchors.right:parent.right
color: FormStyle.header.separator.color
}
}
Item{
id: centerRow
anchors.left:parent.left
anchors.right:parent.right
transformOrigin: Item.Center
layer.wrapMode: ShaderEffectSource.ClampToEdge
height:detailsRow.height
ActionButton {
id:removeldap
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 0
icon: 'cancel'
iconSize:CallsStyle.entry.iconActionSize-2
}
RowLayout{// Details row have its size from children
id:detailsRow
anchors.left: removeldap.right
anchors.right: deleteLdap.left
anchors.rightMargin: 10
anchors.leftMargin: 10
ColumnLayout{
Layout.fillHeight: true
Layout.fillWidth:true
TextField {
id:serverUrl
text: "Server"
Layout.fillWidth: true
placeholderText :"Server"
}
TextField {
text: "Bind DN"
Layout.fillWidth: true
}
TextField {
text: "Password"
Layout.fillWidth: true
}
}
ColumnLayout{
Layout.fillHeight: true
Layout.fillWidth:true
TextField {
text: "Base Object"
Layout.fillWidth: true
}
TextField {
text: "Filter"
Layout.fillWidth: true
}
TextField {
text: "MaxResults"
Layout.fillWidth: true
}
}
ColumnLayout{
Layout.fillHeight: true
Layout.fillWidth:true
TextField {
text: "Names Attributes"
Layout.fillWidth: true
}
TextField {
text: "Sip Attributes"
Layout.fillWidth: true
}
TextField {
text: "Scheme"
Layout.fillWidth: true
}
TextField {
text: "Domain"
Layout.fillWidth: true
}
}
}
Switch {
id: deleteLdap
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 0
checked: false
onClicked: {
checked = !checked
}
}
}
}
states: [
State {
name: "Summary"
when: swipeView.index==1
},
State {
name: "Details"
when: swipeView.index==2
}
]
*/
}
/*##^##
Designer {
D{i:0;autoSize:true;formeditorZoom:0.75;height:480;width:640}
}
##^##*/

@ -1 +1 @@
Subproject commit b1d5c79e31e9b4604a9094ae604143c010051e83
Subproject commit b95fee70fc3456b024a8dc9c00d6adb694c58092