Carddav settings

This commit is contained in:
Christophe Deschamps 2024-10-07 08:39:52 +00:00
parent 2bd5c8a161
commit 11f8163e4b
33 changed files with 1106 additions and 135 deletions

View file

@ -41,8 +41,10 @@
#include "core/account/AccountCore.hpp"
#include "core/account/AccountDeviceGui.hpp"
#include "core/account/AccountDeviceProxy.hpp"
#include "core/address-books/LdapGui.hpp"
#include "core/address-books/LdapProxy.hpp"
#include "core/address-books/carddav/CarddavGui.hpp"
#include "core/address-books/carddav/CarddavProxy.hpp"
#include "core/address-books/ldap/LdapGui.hpp"
#include "core/address-books/ldap/LdapProxy.hpp"
#include "core/call-history/CallHistoryProxy.hpp"
#include "core/call/CallCore.hpp"
#include "core/call/CallGui.hpp"
@ -594,6 +596,8 @@ void App::initCppInterfaces() {
QLatin1String("Uncreatable"));
qmlRegisterType<LdapGui>(Constants::MainQmlUri, 1, 0, "LdapGui");
qmlRegisterType<LdapProxy>(Constants::MainQmlUri, 1, 0, "LdapProxy");
qmlRegisterType<CarddavGui>(Constants::MainQmlUri, 1, 0, "CarddavGui");
qmlRegisterType<CarddavProxy>(Constants::MainQmlUri, 1, 0, "CarddavProxy");
LinphoneEnums::registerMetaTypes();
}

View file

@ -68,10 +68,15 @@ list(APPEND _LINPHONEAPP_SOURCES
core/videoSource/VideoSourceDescriptorCore.cpp
core/videoSource/VideoSourceDescriptorGui.cpp
core/address-books/LdapCore.cpp
core/address-books/LdapGui.cpp
core/address-books/LdapProxy.cpp
core/address-books/LdapList.cpp
core/address-books/ldap/LdapCore.cpp
core/address-books/ldap/LdapGui.cpp
core/address-books/ldap/LdapProxy.cpp
core/address-books/ldap/LdapList.cpp
core/address-books/carddav/CarddavCore.cpp
core/address-books/carddav/CarddavGui.cpp
core/address-books/carddav/CarddavProxy.cpp
core/address-books/carddav/CarddavList.cpp
)

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CarddavCore.hpp"
#include "core/App.hpp"
DEFINE_ABSTRACT_OBJECT(CarddavCore)
QSharedPointer<CarddavCore> CarddavCore::create(const std::shared_ptr<linphone::FriendList> &carddavFriendList) {
auto sharedPointer = QSharedPointer<CarddavCore>(new CarddavCore(carddavFriendList), &QObject::deleteLater);
sharedPointer->setSelf(sharedPointer);
sharedPointer->moveToThread(App::getInstance()->thread());
return sharedPointer;
}
CarddavCore::CarddavCore(const std::shared_ptr<linphone::FriendList> &carddavFriendList) : QObject(nullptr) {
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mCarddavModel = CarddavModel::create(carddavFriendList);
if (carddavFriendList) {
mDisplayName = Utils::coreStringToAppString(carddavFriendList->getDisplayName());
mUri = Utils::coreStringToAppString(carddavFriendList->getUri());
}
mStoreNewFriendsInIt = mCarddavModel->storeNewFriendsInIt();
}
CarddavCore::~CarddavCore() {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
}
void CarddavCore::save() {
if (!mUri.startsWith("http://") && !mUri.startsWith("https://")) {
mUri = "https://" + mUri;
emit uriChanged();
}
auto displayName = Utils::appStringToCoreString(mDisplayName);
auto uri = Utils::appStringToCoreString(mUri);
auto username = Utils::appStringToCoreString(mUsername);
auto password = Utils::appStringToCoreString(mPassword);
auto realm = Utils::appStringToCoreString(mRealm);
auto storeNewFriendsInIt = mStoreNewFriendsInIt;
mCarddavModelConnection->invokeToModel([this, displayName, uri, username, password, realm, storeNewFriendsInIt]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mCarddavModel->save(displayName, uri, username, password, realm, storeNewFriendsInIt);
});
}
void CarddavCore::remove() {
mCarddavModelConnection->invokeToModel([this]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mCarddavModel->remove();
});
}
void CarddavCore::setSelf(QSharedPointer<CarddavCore> me) {
mCarddavModelConnection = QSharedPointer<SafeConnection<CarddavCore, CarddavModel>>(
new SafeConnection<CarddavCore, CarddavModel>(me, mCarddavModel), &QObject::deleteLater);
mCarddavModelConnection->makeConnectToModel(&CarddavModel::saved, [this](bool success) {
mCarddavModelConnection->invokeToCore([this, success]() { emit saved(success); });
});
}
bool CarddavCore::isValid() {
return !mDisplayName.isEmpty() && !mUri.isEmpty(); // Auth info is optional.
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CARDDAV_CORE_H_
#define CARDDAV_CORE_H_
#include "model/address-books/carddav/CarddavModel.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QObject>
#include <QSharedPointer>
#include <linphone++/linphone.hh>
class CarddavCore : public QObject, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<CarddavCore> create(const std::shared_ptr<linphone::FriendList> &carddavFriendList);
CarddavCore(const std::shared_ptr<linphone::FriendList> &carddavFriendList);
~CarddavCore();
void setSelf(QSharedPointer<CarddavCore> me);
Q_INVOKABLE void remove();
Q_INVOKABLE void save();
Q_INVOKABLE bool isValid();
DECLARE_CORE_MEMBER(QString, displayName, DisplayName)
DECLARE_CORE_MEMBER(QString, uri, Uri)
DECLARE_CORE_MEMBER(QString, username, Username)
DECLARE_CORE_MEMBER(QString, password, Password)
DECLARE_CORE_MEMBER(QString, realm, Realm)
DECLARE_CORE_MEMBER(bool, storeNewFriendsInIt, StoreNewFriendsInIt)
signals:
void saved(bool success);
private:
std::shared_ptr<CarddavModel> mCarddavModel;
QSharedPointer<SafeConnection<CarddavCore, CarddavModel>> mCarddavModelConnection;
DECLARE_ABSTRACT_OBJECT
};
Q_DECLARE_METATYPE(CarddavCore *)
#endif

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -105,9 +105,9 @@ void LdapCore::setSelf(QSharedPointer<LdapCore> me) {
debugLevel, DebugLevel)
mLdapModelConnection->makeConnectToModel(&LdapModel::saved, [this]() {
mLdapModelConnection->invokeToCore([this]() { emit App::getInstance() -> getSettings()->ldapConfigChanged(); });
mLdapModelConnection->invokeToCore([this]() { emit App::getInstance()->getSettings()->ldapConfigChanged(); });
});
mLdapModelConnection->makeConnectToModel(&LdapModel::removed, [this]() {
mLdapModelConnection->invokeToCore([this]() { emit App::getInstance() -> getSettings()->ldapConfigChanged(); });
mLdapModelConnection->invokeToCore([this]() { emit App::getInstance()->getSettings()->ldapConfigChanged(); });
});
}

View file

@ -21,7 +21,7 @@
#ifndef LDAP_CORE_H_
#define LDAP_CORE_H_
#include "model/address-books/LdapModel.hpp"
#include "model/address-books/ldap/LdapModel.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QObject>

View file

@ -85,9 +85,7 @@ void LdapList::removeAllEntries() {
void LdapList::remove(const int &row) {
beginRemoveRows(QModelIndex(), row, row);
auto item = mList[row].objectCast<LdapCore>();
item->remove();
mList.takeAt(row);
mList.takeAt(row).objectCast<LdapCore>()->remove();
endRemoveRows();
}

View file

@ -21,7 +21,7 @@
#ifndef LDAP_LIST_H_
#define LDAP_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "../../proxy/ListProxy.hpp"
#include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QLocale>

View file

@ -21,7 +21,7 @@
#ifndef LDAP_PROXY_H_
#define LDAP_PROXY_H_
#include "../proxy/SortFilterProxy.hpp"
#include "../../proxy/SortFilterProxy.hpp"
#include "LdapGui.hpp"
#include "LdapList.hpp"
#include "tool/AbstractObject.hpp"

View file

@ -620,10 +620,15 @@ void FriendCore::save() { // Save Values to model
thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater();
mVCardString = mFriendModel->getVCardAsString();
bool created =
(core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK);
auto carddavListForNewFriends = SettingsModel::getCarddavListForNewFriends();
auto listWhereToAddFriend = carddavListForNewFriends != nullptr ? carddavListForNewFriends
: core->getDefaultFriendList();
bool created = (listWhereToAddFriend->addFriend(contact) == linphone::FriendList::Status::OK);
if (created) {
core->getDefaultFriendList()->updateSubscriptions();
listWhereToAddFriend->updateSubscriptions();
if (listWhereToAddFriend->getType() == linphone::FriendList::Type::CardDAV) {
listWhereToAddFriend->synchronizeFriendsFromServer();
}
emit CoreModel::getInstance()->friendCreated(contact);
}
mCoreModelConnection->invokeToCore([this, created]() {

View file

@ -41,7 +41,9 @@ list(APPEND _LINPHONEAPP_SOURCES
model/videoSource/VideoSourceDescriptorModel.cpp
model/address-books/LdapModel.cpp
model/address-books/ldap/LdapModel.cpp
model/address-books/carddav/CarddavModel.cpp
)
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)

View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CarddavModel.hpp"
#include "model/core/CoreModel.hpp"
#include "model/setting/SettingsModel.hpp"
#include "tool/Utils.hpp"
DEFINE_ABSTRACT_OBJECT(CarddavModel)
using namespace std;
std::shared_ptr<CarddavModel> CarddavModel::create(const std::shared_ptr<linphone::FriendList> &carddavFriendList,
QObject *parent) {
auto model = std::make_shared<CarddavModel>(carddavFriendList, parent);
model->setSelf(model);
return model;
}
CarddavModel::CarddavModel(const std::shared_ptr<linphone::FriendList> &carddavFriendList, QObject *parent)
: ::Listener<linphone::FriendList, linphone::FriendListListener>(nullptr, parent) {
mustBeInLinphoneThread(getClassName());
mCarddavFriendList = carddavFriendList;
mStoreNewFriendsInIt = storeNewFriendsInIt();
mCreatedAuthInfo = nullptr;
mRemovedAuthInfo = nullptr;
}
CarddavModel::~CarddavModel() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
}
bool CarddavModel::storeNewFriendsInIt() {
if (!mCarddavFriendList) return false;
auto carddavListForNewFriends = SettingsModel::getCarddavListForNewFriends();
return carddavListForNewFriends != nullptr &&
mCarddavFriendList->getDisplayName() == carddavListForNewFriends->getDisplayName();
}
void CarddavModel::save(
string displayName, string uri, string username, string password, string realm, bool storeNewFriendsInIt) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
// Auth info handled in lazy mode, if provided handle otherwise ignore.
// TODO: add dialog to ask user before removing existing auth info if existing already - (comment from Android)
if (!username.empty() && !realm.empty()) {
mRemovedAuthInfo = core->findAuthInfo(realm, username, "");
if (mRemovedAuthInfo != nullptr) {
lWarning() << log().arg("Auth info with username ") << username << " already exists, removing it first.";
core->removeAuthInfo(mRemovedAuthInfo);
}
lInfo() << log().arg("Adding auth info with username") << username;
mCreatedAuthInfo = linphone::Factory::get()->createAuthInfo(username, "", password, "", realm, "");
core->addAuthInfo(mCreatedAuthInfo);
} else {
lInfo() << log().arg("No auth info provided upon saving.");
}
if (!mCarddavFriendList) {
mCarddavFriendList = CoreModel::getInstance()->getCore()->createFriendList();
mCarddavFriendList->setType(linphone::FriendList::Type::CardDAV);
mCarddavFriendList->enableDatabaseStorage(true);
core->addFriendList(mCarddavFriendList);
}
mCarddavFriendList->setDisplayName(displayName);
mCarddavFriendList->setUri(uri);
mStoreNewFriendsInIt = storeNewFriendsInIt;
setMonitor(mCarddavFriendList);
mCarddavFriendList->synchronizeFriendsFromServer();
}
void CarddavModel::remove() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
CoreModel::getInstance()->getCore()->removeFriendList(mCarddavFriendList);
lInfo() << log().arg("Friend list removed:") << mCarddavFriendList->getUri();
emit removed();
}
void CarddavModel::onSyncStatusChanged(const std::shared_ptr<linphone::FriendList> &friendList,
linphone::FriendList::SyncStatus status,
const std::string &message) {
if (status == linphone::FriendList::SyncStatus::Successful) {
lInfo() << log().arg("Successfully synchronized:") << mCarddavFriendList->getUri();
setMonitor(nullptr);
if (mStoreNewFriendsInIt) SettingsModel::setCarddavListForNewFriends(friendList->getDisplayName());
emit saved(true);
}
if (status == linphone::FriendList::SyncStatus::Failure) {
lWarning() << log().arg("Synchronization failure:") << mCarddavFriendList->getUri();
setMonitor(nullptr);
emit saved(false);
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CARDDAV_MODEL_H_
#define CARDDAV_MODEL_H_
#include "model/listener/Listener.hpp"
#include "tool/AbstractObject.hpp"
#include <QObject>
#include <linphone++/linphone.hh>
class CarddavModel : public ::Listener<linphone::FriendList, linphone::FriendListListener>,
public linphone::FriendListListener,
public AbstractObject {
Q_OBJECT
public:
static std::shared_ptr<CarddavModel> create(const std::shared_ptr<linphone::FriendList> &carddavFriendList,
QObject *parent = nullptr);
CarddavModel(const std::shared_ptr<linphone::FriendList> &carddavFriendList, QObject *parent = nullptr);
~CarddavModel();
void save(std::string displayName, std::string uri, std::string username, std::string password, std::string realm, bool storeNewFriendsInIt);
void remove();
bool storeNewFriendsInIt();
signals:
void saved(bool success);
void removed();
private:
bool mStoreNewFriendsInIt;
std::shared_ptr<linphone::FriendList> mCarddavFriendList;
std::shared_ptr<const linphone::AuthInfo> mRemovedAuthInfo;
std::shared_ptr<linphone::AuthInfo> mCreatedAuthInfo;
DECLARE_ABSTRACT_OBJECT
//--------------------------------------------------------------------------------
// LINPHONE
//--------------------------------------------------------------------------------
virtual void onSyncStatusChanged(const std::shared_ptr<linphone::FriendList> &friendList,
linphone::FriendList::SyncStatus status,
const std::string &message) override;
};
#endif

View file

@ -399,3 +399,7 @@ void CoreModel::onVersionUpdateCheckResultReceived(const std::shared_ptr<linphon
const std::string &url) {
emit versionUpdateCheckResultReceived(core, result, version, url);
}
void CoreModel::onFriendListRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::FriendList> &friendList) {
emit friendListRemoved(core, friendList);
}

View file

@ -180,6 +180,8 @@ private:
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url) override;
virtual void onFriendListRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::FriendList> &friendList) override;
signals:
void accountAdded(const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account);
@ -260,6 +262,8 @@ signals:
linphone::VersionUpdateCheckResult result,
const std::string &version,
const std::string &url);
void friendListRemoved(const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<linphone::FriendList> &friendList);
};
#endif

View file

@ -502,6 +502,30 @@ void SettingsModel::enableDnd(bool enableDnd) {
emit dndChanged(enableDnd);
}
// =============================================================================
// Carddav storage list
// =============================================================================
const std::shared_ptr<linphone::FriendList> SettingsModel::getCarddavListForNewFriends() {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
if (core) {
auto config = core->getConfig();
auto listName = config->getString(UiSection, "friend_list_to_store_newly_created_contacts", "");
if (!listName.empty()) return core->getFriendListByName(listName);
else return nullptr;
} else return nullptr;
}
void SettingsModel::setCarddavListForNewFriends(std::string name) {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
auto core = CoreModel::getInstance()->getCore();
if (core) {
auto config = core->getConfig();
config->setString(UiSection, "friend_list_to_store_newly_created_contacts", name);
}
}
// =============================================================================
// Ui.
// =============================================================================

View file

@ -127,6 +127,9 @@ public:
QString getLogsEmail() const;
static const std::shared_ptr<linphone::FriendList> getCarddavListForNewFriends();
static void setCarddavListForNewFriends(std::string listName);
// UI
DECLARE_GETSET(bool, disableChatFeature, DisableChatFeature)
DECLARE_GETSET(bool, disableMeetingsFeature, DisableMeetingsFeature)

View file

@ -38,8 +38,7 @@
}
#define DECLARE_GUI_OBJECT \
Q_SIGNALS: \
void qmlNameChanged(); \
Q_SIGNALS : void qmlNameChanged(); \
\
public: \
Q_PROPERTY(QString qmlName READ getQmlName WRITE setQmlName NOTIFY qmlNameChanged) \
@ -67,6 +66,11 @@ public:
Q_SIGNAL void x##Changed(); \
type m##X;
#define DECLARE_CORE_MEMBER(type, x, X) \
Q_PROPERTY(type x MEMBER m##X NOTIFY x##Changed) \
Q_SIGNAL void x##Changed(); \
type m##X;
#define DECLARE_CORE_GETSET(type, x, X) \
Q_PROPERTY(type x READ get##X WRITE set##X NOTIFY x##Changed) \
Q_SIGNAL void set##X(type data); \

View file

@ -104,8 +104,10 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Page/Layout/Settings/AccountSettingsParametersLayout.qml
view/Page/Layout/Settings/CallSettingsLayout.qml
view/Page/Layout/Settings/ContactsSettingsLayout.qml
view/Page/Layout/Settings/ContactsSettingsProviderLayout.qml
view/Page/Layout/Settings/DebugSettingsLayout.qml
view/Page/Layout/Settings/LdapSettingsLayout.qml
view/Page/Layout/Settings/CarddavSettingsLayout.qml
view/Page/Layout/Settings/SecuritySettingsLayout.qml
view/Page/Main/AbstractMainPage.qml

View file

@ -0,0 +1,146 @@
import QtCore
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls.Basic as Control
import QtQuick.Dialogs
import Linphone
import SettingsCpp 1.0
import UtilsCpp
AbstractSettingsLayout {
id: mainItem
contentComponent: content
topbarOptionalComponent: topBar
property alias carddavGui: mainItem.model
property bool isNew: false
Component {
id: topBar
RowLayout {
spacing: 20 * DefaultStyle.dp
Button {
background: Item{}
icon.source: AppIcons.trashCan
icon.width: 32 * DefaultStyle.dp
icon.height: 32 * DefaultStyle.dp
contentImageColor: DefaultStyle.main2_600
visible: !isNew
onClicked: {
var mainWin = UtilsCpp.getMainWindow()
mainWin.showConfirmationLambdaPopup(
qsTr("Supprimer le carnet d'adresse CardDAV ?"),
"",
function (confirmed) {
if (confirmed) {
carddavGui.core.remove()
mainItem.container.pop()
}
}
)
}
}
Button {
text: qsTr("Enregistrer")
onClicked: {
if (carddavGui.core.isValid()) {
carddavGui.core.save()
} else {
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Vérifiez que toutes les informations ont été saisies."), false, mainWindow)
}
}
Connections {
target: carddavGui.core
function onSaved(success) {
if (success)
UtilsCpp.showInformationPopup(qsTr("Succès"), qsTr("Le carnet d'adresse CardDAV est synchronisé."), true, mainWindow)
else
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("Erreur de synchronisation!"), false, mainWindow)
}
}
}
}
}
Component {
id: content
ColumnLayout {
width: parent.width
spacing: 5 * DefaultStyle.dp
RowLayout {
Layout.topMargin: 16 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
Layout.minimumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
Layout.fillWidth: true
text: qsTr("Carnet d'adresse CardDAV")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
}
Text {
text: qsTr("Ajouter un carnet dadresse CardDAV pour synchroniser vos contacts Linphone avec un carnet dadresse tiers.")
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 20 * DefaultStyle.dp
Layout.rightMargin: 44 * DefaultStyle.dp
Layout.topMargin: 20 * DefaultStyle.dp
Layout.leftMargin: 64 * DefaultStyle.dp
DecoratedTextField {
propertyName: "displayName"
propertyOwner: carddavGui.core
title: qsTr("Nom daffichage")
canBeEmpty: false
toValidate: true
}
DecoratedTextField {
propertyName: "uri"
propertyOwner: carddavGui.core
title: qsTr("URL du serveur")
canBeEmpty: false
toValidate: true
}
DecoratedTextField {
propertyName: "username"
propertyOwner: carddavGui.core
title: qsTr("Nom dutilisateur")
toValidate: true
}
DecoratedTextField {
propertyName: "password"
hidden: true
propertyOwner: carddavGui.core
title: qsTr("Mot de passe")
toValidate: true
}
DecoratedTextField {
propertyName: "realm"
propertyOwner: carddavGui.core
title: qsTr("Domaine dauthentification")
toValidate: true
}
SwitchSetting {
titleText: qsTr("Stocker ici les contacts nouvellement crées")
propertyName: "storeNewFriendsInIt"
propertyOwner: carddavGui.core
}
}
}
}
}
}

View file

@ -11,127 +11,51 @@ AbstractSettingsLayout {
function layoutUrl(name) {
return layoutsPath+"/"+name+".qml"
}
function createGuiObject(name) {
return Qt.createQmlObject('import Linphone; '+name+'Gui{}', mainItem)
}
Component {
id: content
RowLayout {
ColumnLayout {
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
text: qsTr("Annuaires LDAP")
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
Text {
text: qsTr("Ajouter vos annuaires LDAP pour pouvoir effectuer des recherches dans la magic search bar.")
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
ContactsSettingsProviderLayout {
title: qsTr("Annuaires LDAP")
addText: qsTr("Ajouter un annuaire LDAP")
addTextDescription: qsTr("Ajouter vos annuaires LDAP pour pouvoir effectuer des recherches dans la magic search bar.")
editText: qsTr("Modifier un annuaire LDAP")
proxyModel: LdapProxy {}
newItemGui: createGuiObject('Ldap')
settingsLayout: layoutUrl("LdapSettingsLayout")
owner: mainItem
titleProperty: "server"
supportsEnableDisable: true
showAddButton: true
}
ColumnLayout {
Layout.rightMargin: 25 * DefaultStyle.dp
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 27 * DefaultStyle.dp
Layout.leftMargin: 76 * DefaultStyle.dp
Layout.topMargin: 16 * DefaultStyle.dp
Repeater {
model: LdapProxy {
id: proxyModel
}
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft|Qt.AlignHCenter
spacing: 5 * DefaultStyle.dp
Text {
text: modelData.core.server
font: Typography.p2l
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
Layout.leftMargin: 17 * DefaultStyle.dp
}
Item {
Layout.fillWidth: true
}
Button {
background: Item{}
icon.source: AppIcons.pencil
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
contentImageColor: DefaultStyle.main2_600
onClicked: {
var ldapGui = Qt.createQmlObject('import Linphone
LdapGui{
}', mainItem)
mainItem.container.push(layoutUrl("LdapSettingsLayout"), {
titleText: qsTr("Modifier un annuaire LDAP"),
model: modelData,
container: mainItem.container,
isNew: false})
}
}
Switch {
id: switchButton
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: 17 * DefaultStyle.dp
checked: modelData.core["enabled"]
onToggled: {
binding.when = true
modelData.core.save()
}
}
Binding {
id: binding
target: modelData.core
property: "enabled"
value: switchButton.checked
when: false
}
}
onVisibleChanged: {
proxyModel.updateView()
}
Component.onCompleted: {
proxyModel.updateView()
}
}
RowLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
Item {
Layout.fillWidth: true
}
Button {
Layout.alignment: Qt.AlignRight | Qt.AlignHCenter
text: qsTr("Ajouter")
onClicked: {
var ldapGui = Qt.createQmlObject('import Linphone
LdapGui{
}', mainItem)
mainItem.container.push(layoutUrl("LdapSettingsLayout"), {
titleText: qsTr("Ajouter un annuaire LDAP"),
model: ldapGui,
container: mainItem.container,
isNew: true})
}
}
}
Layout.topMargin: 35 * DefaultStyle.dp
Layout.bottomMargin: 9 * DefaultStyle.dp
height: 1 * DefaultStyle.dp
color: DefaultStyle.main2_500main
}
ContactsSettingsProviderLayout {
id: carddavProvider
title: qsTr("Carnet d'adresse CardDAV")
addText: qsTr("Ajouter un carnet d'adresse CardDAV")
addTextDescription: qsTr("Ajouter un carnet dadresse CardDAV pour synchroniser vos contacts Linphone avec un carnet dadresse tiers.")
editText: qsTr("Modifier un carnet d'adresse CardDAV")
proxyModel: CarddavProxy {
onModelReset: {
carddavProvider.showAddButton = carddavProvider.proxyModel.count == 0
carddavProvider.newItemGui = createGuiObject('Carddav')
}
}
newItemGui: createGuiObject('Carddav')
settingsLayout: layoutUrl("CarddavSettingsLayout")
owner: mainItem
titleProperty: "displayName"
supportsEnableDisable: false
}
}
}
}

View file

@ -0,0 +1,135 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls.Basic as Control
import SettingsCpp 1.0
import Linphone
RowLayout {
id: mainItem
property string title
property string addText
property string addTextDescription
property string editText
property var newItemGui
property string settingsLayout
property var proxyModel
property var owner
property string titleProperty
property bool supportsEnableDisable
property bool showAddButton
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
ColumnLayout {
Layout.preferredWidth: 341 * DefaultStyle.dp
Layout.maximumWidth: 341 * DefaultStyle.dp
spacing: 5 * DefaultStyle.dp
Text {
text: mainItem.title
font: Typography.h4
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
Text {
text: mainItem.addTextDescription
font: Typography.p1s
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
}
}
Item {
Layout.fillHeight: true
}
}
ColumnLayout {
Layout.rightMargin: 25 * DefaultStyle.dp
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 27 * DefaultStyle.dp
Layout.leftMargin: 76 * DefaultStyle.dp
Layout.topMargin: 16 * DefaultStyle.dp
Repeater {
model: mainItem.proxyModel
RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignLeft|Qt.AlignHCenter
spacing: 5 * DefaultStyle.dp
Text {
text: modelData.core[titleProperty]
font: Typography.p2l
wrapMode: Text.WordWrap
color: DefaultStyle.main2_600
Layout.fillWidth: true
Layout.leftMargin: 17 * DefaultStyle.dp
}
Item {
Layout.fillWidth: true
}
Button {
background: Item{}
icon.source: AppIcons.pencil
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
contentImageColor: DefaultStyle.main2_600
onClicked: {
mainItem.owner.container.push(mainItem.settingsLayout, {
titleText: mainItem.editText,
model: modelData,
container: mainItem.owner.container,
isNew: false})
}
}
Switch {
id: switchButton
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: 17 * DefaultStyle.dp
checked: supportsEnableDisable && modelData.core["enabled"]
visible: supportsEnableDisable
onToggled: {
binding.when = true
modelData.core.save()
}
}
Binding {
id: binding
target: modelData.core
property: "enabled"
value: switchButton.checked
when: false
}
}
onVisibleChanged: {
proxyModel.updateView()
}
Component.onCompleted: {
proxyModel.updateView()
}
}
RowLayout {
Layout.fillWidth: true
spacing: 5 * DefaultStyle.dp
Item {
Layout.fillWidth: true
}
Button {
Layout.preferredHeight: 47 * DefaultStyle.dp
Layout.alignment: Qt.AlignRight | Qt.AlignHCenter
text: qsTr("Ajouter")
visible: mainItem.showAddButton
onClicked: {
mainItem.owner.container.push(mainItem.settingsLayout, {
titleText: mainItem.addText,
model: mainItem.newItemGui,
container: mainItem.owner.container,
isNew: true})
}
}
}
}
}