diff --git a/CMakeLists.txt b/CMakeLists.txt index e74924af9..0a4cff0e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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")) diff --git a/linphone-app/CMakeLists.txt b/linphone-app/CMakeLists.txt index 66aa6b4cc..7c6dddd97 100644 --- a/linphone-app/CMakeLists.txt +++ b/linphone-app/CMakeLists.txt @@ -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}) diff --git a/linphone-app/resources.qrc b/linphone-app/resources.qrc index 1948cf996..71be89744 100644 --- a/linphone-app/resources.qrc +++ b/linphone-app/resources.qrc @@ -489,5 +489,9 @@ ui/dev-modules/Colors/Colors.qml ui/dev-modules/Units/Units.qml assets/icon.ico + ui/views/App/Settings/SettingsLdap.qml + ui/views/App/Settings/SettingsLdapDescription.qml + ui/views/App/Settings/Dialogs/SettingsLdapEdit.qml + ui/views/App/Settings/Dialogs/SettingsLdapEdit.js diff --git a/linphone-app/src/app/App.cpp b/linphone-app/src/app/App.cpp index 83a8610c6..487dfb451 100644 --- a/linphone-app/src/app/App.cpp +++ b/linphone-app/src/app/App.cpp @@ -579,6 +579,8 @@ void App::registerTypes () { qRegisterMetaType>(); qRegisterMetaType(); + qRegisterMetaType>(); + qRegisterMetaType > >(); registerType("AssistantModel"); registerType("AuthenticationNotifier"); @@ -593,7 +595,10 @@ void App::registerTypes () { registerType("FileDownloader"); registerType("FileExtractor"); registerType("HistoryProxyModel"); + registerType("LdapProxyModel"); registerType("SipAddressesProxyModel"); + registerType("SearchSipAddressesModel"); + registerType("SoundPlayer"); registerType("TelephoneNumbersModel"); @@ -610,6 +615,7 @@ void App::registerTypes () { registerUncreatableType("ContactModel"); registerUncreatableType("ContactsImporterModel"); registerUncreatableType("HistoryModel"); + registerUncreatableType("LdapModel"); registerUncreatableType("SipAddressObserver"); registerUncreatableType("VcardModel"); } @@ -625,6 +631,7 @@ void App::registerSharedTypes () { registerSharedSingletonType("CallsListModel"); registerSharedSingletonType("ContactsListModel"); registerSharedSingletonType("ContactsImporterListModel"); + registerSharedSingletonType("LdapListModel"); } void App::registerToolTypes () { diff --git a/linphone-app/src/components/Components.hpp b/linphone-app/src/components/Components.hpp index 9848d6465..1569720ae 100644 --- a/linphone-app/src/components/Components.hpp +++ b/linphone-app/src/components/Components.hpp @@ -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" diff --git a/linphone-app/src/components/call/CallModel.cpp b/linphone-app/src/components/call/CallModel.cpp index b62d7c863..f1b696b49 100644 --- a/linphone-app/src/components/call/CallModel.cpp +++ b/linphone-app/src/components/call/CallModel.cpp @@ -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 call) { +void CallModel::searchReceived(std::list> 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 call){ Q_CHECK_PTR(call); mCall = call; mCall->setData("call-model", *this); + updateIsInConference(); @@ -78,23 +105,34 @@ CallModel::CallModel (shared_ptr call) { coreHandlers, &CoreHandlers::callEncryptionChanged, this, &CallModel::handleCallEncryptionChanged ); +// Update fields + mMagicSearch = CoreManager::getInstance()->getCore()->createMagicSearch(); + mSearch = std::make_shared(this); + QObject::connect(mSearch.get(), SIGNAL(searchReceived(std::list> )), this, SLOT(searchReceived(std::list>))); + 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 { diff --git a/linphone-app/src/components/call/CallModel.hpp b/linphone-app/src/components/call/CallModel.hpp index 7a93c738b..723ec9c35 100644 --- a/linphone-app/src/components/call/CallModel.hpp +++ b/linphone-app/src/components/call/CallModel.hpp @@ -23,7 +23,7 @@ #include #include - +#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 mCall; + std::shared_ptr mRemoteAddress; + std::shared_ptr mMagicSearch; + +public slots: + void searchReceived(std::list> 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 &call); void handleCallStateChanged (const std::shared_ptr &call, linphone::Call::State state); + + void accept (bool withVideo); @@ -230,8 +243,8 @@ private: QVariantList mAudioStats; QVariantList mVideoStats; + std::shared_ptr mSearch; - std::shared_ptr mCall; }; #endif // CALL_MODEL_H_ diff --git a/linphone-app/src/components/core/CoreManager.cpp b/linphone-app/src/components/core/CoreManager.cpp index c0ae54dcf..cc61a6fae 100644 --- a/linphone-app/src/components/core/CoreManager.cpp +++ b/linphone-app/src/components/core/CoreManager.cpp @@ -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 dns; + //dns.push_back("10.0.3.50"); + //mCore->setDnsServers(dns); + qInfo() << QStringLiteral("CoreManager initialized"); emit coreManagerInitialized(); } diff --git a/linphone-app/src/components/core/CoreManager.hpp b/linphone-app/src/components/core/CoreManager.hpp index 6b08e1d61..261b85e22 100644 --- a/linphone-app/src/components/core/CoreManager.hpp +++ b/linphone-app/src/components/core/CoreManager.hpp @@ -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, std::weak_ptr> mChatModels; HistoryModel * mHistoryModel = nullptr; + LdapListModel *mLdapListModel = nullptr; QTimer *mCbsTimer = nullptr; diff --git a/linphone-app/src/components/ldap/LdapListModel.cpp b/linphone-app/src/components/ldap/LdapListModel.cpp new file mode 100644 index 000000000..19e4fe311 --- /dev/null +++ b/linphone-app/src/components/ldap/LdapListModel.cpp @@ -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 . + */ + +#include +#include +#include +#include + +#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 LdapListModel::roleNames () const { + QHash 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); + } +} diff --git a/linphone-app/src/components/ldap/LdapListModel.hpp b/linphone-app/src/components/ldap/LdapListModel.hpp new file mode 100644 index 000000000..ba0ff4a2c --- /dev/null +++ b/linphone-app/src/components/ldap/LdapListModel.hpp @@ -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 . + */ + +#ifndef LDAP_LIST_MODEL_H_ +#define LDAP_LIST_MODEL_H_ + +#include +#include + +#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 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 mServers; +}; + +#endif // LDAP_LIST_MODEL_H_ diff --git a/linphone-app/src/components/ldap/LdapModel.cpp b/linphone-app/src/components/ldap/LdapModel.cpp new file mode 100644 index 000000000..09bfe7cdf --- /dev/null +++ b/linphone-app/src/components/ldap/LdapModel.cpp @@ -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 . + */ + +#include +#include +#include +#include + +#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(); + } +} diff --git a/linphone-app/src/components/ldap/LdapModel.hpp b/linphone-app/src/components/ldap/LdapModel.hpp new file mode 100644 index 000000000..47b177e98 --- /dev/null +++ b/linphone-app/src/components/ldap/LdapModel.hpp @@ -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 . + */ + +#ifndef LDAP_MODEL_H_ +#define LDAP_MODEL_H_ + +#include +#include + + +// ============================================================================= + +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_ diff --git a/linphone-app/src/components/ldap/LdapProxyModel.cpp b/linphone-app/src/components/ldap/LdapProxyModel.cpp new file mode 100644 index 000000000..d6cd4d05f --- /dev/null +++ b/linphone-app/src/components/ldap/LdapProxyModel.cpp @@ -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 . + */ + +#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(); + const LdapModel* ldapB = sourceModel()->data(right).value(); + + return ldapA->mId <= ldapB->mId; +} diff --git a/linphone-app/src/components/ldap/LdapProxyModel.hpp b/linphone-app/src/components/ldap/LdapProxyModel.hpp new file mode 100644 index 000000000..39925bbd9 --- /dev/null +++ b/linphone-app/src/components/ldap/LdapProxyModel.hpp @@ -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 . + */ + +#ifndef LDAP_PROXY_MODEL_H_ +#define LDAP_PROXY_MODEL_H_ + +#include + +// ============================================================================= + +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_ diff --git a/linphone-app/src/components/search/SearchHandler.cpp b/linphone-app/src/components/search/SearchHandler.cpp new file mode 100644 index 000000000..bdad44900 --- /dev/null +++ b/linphone-app/src/components/search/SearchHandler.cpp @@ -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 . + */ +#include "SearchHandler.hpp" + +#include "linphone/api/c-search-result.h" + +// ============================================================================= + +SearchHandler::SearchHandler(QObject * parent) : QObject(parent){ +} + +void SearchHandler::onSearchResultsReceived(const std::shared_ptr & magicSearch){ + emit searchReceived(magicSearch->getLastSearch()); +} diff --git a/linphone-app/src/components/search/SearchHandler.hpp b/linphone-app/src/components/search/SearchHandler.hpp new file mode 100644 index 000000000..1a7256312 --- /dev/null +++ b/linphone-app/src/components/search/SearchHandler.hpp @@ -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 . + */ + +#ifndef SEARCH_HANDLER_H_ +#define SEARCH_HANDLER_H_ + +#include +#include + +#include +// ============================================================================= +class SearchHandler : public QObject, public linphone::MagicSearchListener{ +Q_OBJECT +public: + SearchHandler(QObject * parent = nullptr); + virtual void onSearchResultsReceived(const std::shared_ptr & magicSearch); +signals: + void searchReceived(std::list> ); +}; +Q_DECLARE_METATYPE(std::shared_ptr); +#endif // SEARCH_HANDLER_H_ diff --git a/linphone-app/src/components/settings/AccountSettingsModel.cpp b/linphone-app/src/components/settings/AccountSettingsModel.cpp index e797ee721..f3473c2ab 100644 --- a/linphone-app/src/components/settings/AccountSettingsModel.cpp +++ b/linphone-app/src/components/settings/AccountSettingsModel.cpp @@ -397,7 +397,7 @@ QVariantList AccountSettingsModel::getAccounts () const { shared_ptr 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()); diff --git a/linphone-app/src/components/settings/SettingsModel.cpp b/linphone-app/src/components/settings/SettingsModel.cpp index c5e1d6dd9..51d887ac1 100644 --- a/linphone-app/src/components/settings/SettingsModel.cpp +++ b/linphone-app/src/components/settings/SettingsModel.cpp @@ -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. // ============================================================================= diff --git a/linphone-app/src/components/settings/SettingsModel.hpp b/linphone-app/src/components/settings/SettingsModel.hpp index 20b0dfe65..b92671df4 100644 --- a/linphone-app/src/components/settings/SettingsModel.hpp +++ b/linphone-app/src/components/settings/SettingsModel.hpp @@ -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. --------------------------------------------------------------------------- diff --git a/linphone-app/src/components/sip-addresses/SearchSipAddressesModel.cpp b/linphone-app/src/components/sip-addresses/SearchSipAddressesModel.cpp new file mode 100644 index 000000000..a9e94ffc8 --- /dev/null +++ b/linphone-app/src/components/sip-addresses/SearchSipAddressesModel.cpp @@ -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 . + */ + +#include +#include +#include +#include + +#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(this); + QObject::connect(mSearch.get(), SIGNAL(searchReceived(std::list> )), this, SLOT(searchReceived(std::list>))); + mMagicSearch->addListener(mSearch); + +} +SearchSipAddressesModel::~SearchSipAddressesModel(){ + + mMagicSearch->removeListener(mSearch); + +} +// ----------------------------------------------------------------------------- + +int SearchSipAddressesModel::rowCount (const QModelIndex &) const { + return mAddresses.count()-1; +} + +QHash SearchSipAddressesModel::roleNames () const { + QHash 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::shared_ptr > > searches; +class DeleteMagic{ +public: + std::shared_ptr magic; + std::shared_ptr 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> 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;*/ +} diff --git a/linphone-app/src/components/sip-addresses/SearchSipAddressesModel.hpp b/linphone-app/src/components/sip-addresses/SearchSipAddressesModel.hpp new file mode 100644 index 000000000..c245d2e86 --- /dev/null +++ b/linphone-app/src/components/sip-addresses/SearchSipAddressesModel.hpp @@ -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 . + */ + +#ifndef SEARCH_SIP_ADDRESSES_MODEL_H_ +#define SEARCH_SIP_ADDRESSES_MODEL_H_ + +#include +#include +#include + +#include + +#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 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 mMagicSearch; + std::shared_ptr mSearch; + +public slots: + void searchReceived(std::list> 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_ diff --git a/linphone-app/src/components/sip-addresses/SearchSipAddressesProxyModel.cpp b/linphone-app/src/components/sip-addresses/SearchSipAddressesProxyModel.cpp new file mode 100644 index 000000000..ee82be780 --- /dev/null +++ b/linphone-app/src/components/sip-addresses/SearchSipAddressesProxyModel.cpp @@ -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 . + */ + +#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(); + const ContactModel *contactB = mapB.value("contact").value(); + + // 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(); + 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; +} diff --git a/linphone-app/src/components/sip-addresses/SearchSipAddressesProxyModel.hpp b/linphone-app/src/components/sip-addresses/SearchSipAddressesProxyModel.hpp new file mode 100644 index 000000000..ffdbef363 --- /dev/null +++ b/linphone-app/src/components/sip-addresses/SearchSipAddressesProxyModel.hpp @@ -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 . + */ + +#ifndef SEARCH_SIP_ADDRESSES_PROXY_MODEL_H_ +#define SEARCH_SIP_ADDRESSES_PROXY_MODEL_H_ + +#include + +// ============================================================================= + +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_ diff --git a/linphone-app/ui/modules/Common/Form/Fields/TextField.qml b/linphone-app/ui/modules/Common/Form/Fields/TextField.qml index 0ecc35df6..ff86e8d9b 100644 --- a/linphone-app/ui/modules/Common/Form/Fields/TextField.qml +++ b/linphone-app/ui/modules/Common/Form/Fields/TextField.qml @@ -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 + } } diff --git a/linphone-app/ui/modules/Common/Form/Placements/Form.qml b/linphone-app/ui/modules/Common/Form/Placements/Form.qml index 9cf99c976..4aab908bb 100644 --- a/linphone-app/ui/modules/Common/Form/Placements/Form.qml +++ b/linphone-app/ui/modules/Common/Form/Placements/Form.qml @@ -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 { diff --git a/linphone-app/ui/modules/Common/Form/Placements/FormLine.qml b/linphone-app/ui/modules/Common/Form/Placements/FormLine.qml index bb79ddd17..e05f564f4 100644 --- a/linphone-app/ui/modules/Common/Form/Placements/FormLine.qml +++ b/linphone-app/ui/modules/Common/Form/Placements/FormLine.qml @@ -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 diff --git a/linphone-app/ui/modules/Common/Form/Switch.qml b/linphone-app/ui/modules/Common/Form/Switch.qml index c83ffca56..e4a922f61 100644 --- a/linphone-app/ui/modules/Common/Form/Switch.qml +++ b/linphone-app/ui/modules/Common/Form/Switch.qml @@ -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 // --------------------------------------------------------------------------- diff --git a/linphone-app/ui/modules/Common/qmldir b/linphone-app/ui/modules/Common/qmldir index fc8cc3d76..9706c5a4d 100644 --- a/linphone-app/ui/modules/Common/qmldir +++ b/linphone-app/ui/modules/Common/qmldir @@ -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 diff --git a/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml b/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml index 6a4b0ed70..1404bb841 100644 --- a/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml +++ b/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml @@ -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 : '') } // --------------------------------------------------------------------- diff --git a/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml b/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml index f00c6fdbd..d845e44d2 100644 --- a/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml +++ b/linphone-app/ui/modules/Linphone/SmartSearchBar/SmartSearchBar.qml @@ -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() diff --git a/linphone-app/ui/views/App/Calls/Dialogs/CallSipAddress.qml b/linphone-app/ui/views/App/Calls/Dialogs/CallSipAddress.qml index d27cda95a..34f39e349 100644 --- a/linphone-app/ui/views/App/Calls/Dialogs/CallSipAddress.qml +++ b/linphone-app/ui/views/App/Calls/Dialogs/CallSipAddress.qml @@ -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 } diff --git a/linphone-app/ui/views/App/Calls/Dialogs/CallTransfer.qml b/linphone-app/ui/views/App/Calls/Dialogs/CallTransfer.qml index 0648d9ee3..ac399c348 100644 --- a/linphone-app/ui/views/App/Calls/Dialogs/CallTransfer.qml +++ b/linphone-app/ui/views/App/Calls/Dialogs/CallTransfer.qml @@ -88,7 +88,7 @@ DialogPlus { genSipAddress: filter.text - model: SipAddressesProxyModel { + model: SearchSipAddressesModel { id: sipAddressesModel } diff --git a/linphone-app/ui/views/App/Calls/Incall.qml b/linphone-app/ui/views/App/Calls/Incall.qml index 0c778c905..ff24d1f71 100644 --- a/linphone-app/ui/views/App/Calls/Incall.qml +++ b/linphone-app/ui/views/App/Calls/Incall.qml @@ -420,7 +420,7 @@ Rectangle { } ActionButton { - icon: SettingsModel.chatEnabled ? 'chat' : 'history' + icon: SettingsModel.chatEnabled && SettingsModel.showStartChatButton ? 'chat' : 'history' onClicked: { if (window.chatIsOpened) { diff --git a/linphone-app/ui/views/App/Main/Contacts.qml b/linphone-app/ui/views/App/Main/Contacts.qml index 378c5a776..553a3c9b6 100644 --- a/linphone-app/ui/views/App/Main/Contacts.qml +++ b/linphone-app/ui/views/App/Main/Contacts.qml @@ -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() } } diff --git a/linphone-app/ui/views/App/Main/Conversation.qml b/linphone-app/ui/views/App/Main/Conversation.qml index f1d8cfffb..c5b81b335 100644 --- a/linphone-app/ui/views/App/Main/Conversation.qml +++ b/linphone-app/ui/views/App/Main/Conversation.qml @@ -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) } diff --git a/linphone-app/ui/views/App/Main/HistoryView.qml b/linphone-app/ui/views/App/Main/HistoryView.qml index 837bfc5ba..6429052c0 100644 --- a/linphone-app/ui/views/App/Main/HistoryView.qml +++ b/linphone-app/ui/views/App/Main/HistoryView.qml @@ -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) } diff --git a/linphone-app/ui/views/App/Settings/Dialogs/SettingsLdapEdit.js b/linphone-app/ui/views/App/Settings/Dialogs/SettingsLdapEdit.js new file mode 100644 index 000000000..033b32e1c --- /dev/null +++ b/linphone-app/ui/views/App/Settings/Dialogs/SettingsLdapEdit.js @@ -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 . + */ +// ============================================================================= +// `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 + }*/ +} + +// ----------------------------------------------------------------------------- diff --git a/linphone-app/ui/views/App/Settings/Dialogs/SettingsLdapEdit.qml b/linphone-app/ui/views/App/Settings/Dialogs/SettingsLdapEdit.qml new file mode 100644 index 000000000..be602c654 --- /dev/null +++ b/linphone-app/ui/views/App/Settings/Dialogs/SettingsLdapEdit.qml @@ -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)' + } + } + } + } + } + } + } +} diff --git a/linphone-app/ui/views/App/Settings/SettingsAdvanced.js b/linphone-app/ui/views/App/Settings/SettingsAdvanced.js index a13e07ac9..aeca0562a 100644 --- a/linphone-app/ui/views/App/Settings/SettingsAdvanced.js +++ b/linphone-app/ui/views/App/Settings/SettingsAdvanced.js @@ -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'), diff --git a/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml b/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml index 5ca27a6ab..978443d57 100644 --- a/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml +++ b/linphone-app/ui/views/App/Settings/SettingsAdvanced.qml @@ -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} +} +##^##*/ diff --git a/linphone-app/ui/views/App/Settings/SettingsLdap.qml b/linphone-app/ui/views/App/Settings/SettingsLdap.qml new file mode 100644 index 000000000..291e0074b --- /dev/null +++ b/linphone-app/ui/views/App/Settings/SettingsLdap.qml @@ -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 + } + } + + } + } + } + } +} diff --git a/linphone-app/ui/views/App/Settings/SettingsLdapDescription.qml b/linphone-app/ui/views/App/Settings/SettingsLdapDescription.qml new file mode 100644 index 000000000..d14cfa5b8 --- /dev/null +++ b/linphone-app/ui/views/App/Settings/SettingsLdapDescription.qml @@ -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} +} +##^##*/ diff --git a/linphone-sdk b/linphone-sdk index b1d5c79e3..b95fee70f 160000 --- a/linphone-sdk +++ b/linphone-sdk @@ -1 +1 @@ -Subproject commit b1d5c79e31e9b4604a9094ae604143c010051e83 +Subproject commit b95fee70fc3456b024a8dc9c00d6adb694c58092