b4435ce13b
This patch makes the configuration layout with per-source and per-peer properties the default for new configurations. Migrating old configurations is not implemented. The command line has not been updated at all (MB #8048). The D-Bus API is fairly complete, only listing sessions independently of a peer is missing (MB #8049). The key concept of this patch is that a pseudo-node implemented by MultiplexConfigNode provides a view on all user-visible or hidden properties. Based on the property name, it looks up the property definition, picks one of the underlying nodes based on the property visibility and sharing attributes, then reads and writes the property via that node. Clearing properties is not needed and not implemented, because of the uncertain semantic (really remove shared properties?!). The "sync" property must be available both in the per-source config (to pick a backend independently of a specific peer) and in the per-peer configuration (to select a specific data format). This is solved by making the property special (SHARED_AND_UNSHARED flag) and then writing it into two nodes. Reading is done from the more specific per-peer node, with the other node acting as fallback. The MultiplexConfigNode has to implement the FilterConfigNode API because it is used as one by the code which sets passwords in the filter. For this to work, the base FilterConfigNode implementation must use virtual method calls. The TestDBusSessionConfig.testUpdateConfigError checks that the error generated for an incorrect "sync" property contains the path of the config.ini file. The meaning of the error message in this case is that the wrong value is *for* that file, not that the property is already wrong *in* the file, but that's okay. The MultiplexConfigNode::getName() can only return a fixed name. To satisfy the test and because it is the right choice at the moment for all properties which might trigger such an error, it now is configured so that it returns the most specific path of the non-shared properties. "syncevolution --print-config" shows errors that are in files. Wrong command line parameters are rejected with a message that refers to the command line parameter ("--source-property sync=foo"). A future enhancement would be to make the name depend on the property (MB#8037). Because an empty string is now a valid configuration name (referencing the source properties without the per-peer properties) several checks for such empty strings were removed. The corresponding tests were updated resp. removed. Instead of talking about "server not found", the more neutral name "configuration" is used. The new TestMultipleConfigs.testSharing() covers the semantic of sharing properties between multiple configs. Access to non-existant nodes is routed into the new DevNullConfigNode. It always returns an empty string when reading and throws an error when trying to write into it. Unintentionally writing into a config.ini file therefore became harder, compared with the previous instantiation of SyncContext() with empty config name. The parsing of incoming messages uses a SyncContext which is bound to a VolatileConfigNode. This allows reading and writing of properties without any risk of touching files on disk. The patch which introduced the new config nodes was not complete yet with regards to the new layout. Removing nodes and trees used the wrong root path: getRootPath() refers to the most specific peer config, m_root to the part without the peer path. SyncConfig must distinguish between a view with peer-specific properties and one without, which is done by setting the m_peerPath only if a peer was selected. Copying properties must know whether writing per-specific properties ("unshared") is wanted, because trying to do it for a view without those properties would trigger the DevNullConfigNode exception. SyncConfig::removeSyncSource() removes source properties both in the shared part of the config and in *all* peers. This is used by Session.SetConfig() for the case that the caller is a) setting instead of updating the config and b) not providing any properties for the source. This is clearly a risky operation which should not be done when there are other peers which still use the source. We might have a problem in our D-Bus API definition for "removing a peer configuration" (MB #8059) because it always has an effect on other peers. The property registries were initialized implicitly before. With the recent changes it happened that SyncContext was initialized to analyze a SyncML message without initializing the registry, which caused getRemoteDevID() to use a property where the hidden flag had not been set yet. Moving all of these additional flags into the property constructors is awkward (which is why they are in the getRegistry() methods), so this was fixed by initializing the properties in the SyncConfig constructors by asking for the registries. Because there is no way to access them except via the registry and SyncConfig instances (*), this should ensure that the properties are valid when used. (*) Exception are some properties which are declared publicly to have access to their name. Nobody's perfect...
173 lines
4.8 KiB
C++
173 lines
4.8 KiB
C++
/*
|
|
* Copyright (C) 2009 Intel Corporation
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) version 3.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*/
|
|
|
|
#include <syncevo/MultiplexConfigNode.h>
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
|
|
SE_BEGIN_CXX
|
|
|
|
FilterConfigNode *
|
|
MultiplexConfigNode::getNode(const string &property,
|
|
const ConfigProperty **found) const
|
|
{
|
|
BOOST_FOREACH(const ConfigProperty *prop, m_registry) {
|
|
if (boost::iequals(prop->getName(), property)) {
|
|
if (found) {
|
|
*found = prop;
|
|
}
|
|
|
|
FilterConfigNode *node =
|
|
m_nodes[prop->isHidden()][prop->getSharing()].get();
|
|
|
|
// special case: fall back to shared node if no unshared
|
|
// node, and property isprimarily stored unshared, but
|
|
// also in the shared node
|
|
if (!node &&
|
|
(prop->getFlags() & ConfigProperty::SHARED_AND_UNSHARED)) {
|
|
node = m_nodes[prop->isHidden()][ConfigProperty::SOURCE_SET_SHARING].get();
|
|
}
|
|
|
|
return node;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void MultiplexConfigNode::addFilter(const string &property,
|
|
const string &value)
|
|
{
|
|
FilterConfigNode::addFilter(property, value);
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e]) {
|
|
m_nodes[i][e]->addFilter(property, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MultiplexConfigNode::setFilter(const ConfigFilter &filter)
|
|
{
|
|
FilterConfigNode::setFilter(filter);
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e]) {
|
|
m_nodes[i][e]->setFilter(filter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MultiplexConfigNode::flush()
|
|
{
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e]) {
|
|
m_nodes[i][e]->flush();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
string MultiplexConfigNode::readProperty(const string &property) const
|
|
{
|
|
FilterConfigNode *node = getNode(property);
|
|
if (node) {
|
|
return node->readProperty(property);
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
void MultiplexConfigNode::setProperty(const string &property,
|
|
const string &value,
|
|
const string &comment,
|
|
const string *defValue)
|
|
{
|
|
const ConfigProperty *prop;
|
|
FilterConfigNode *node = getNode(property, &prop);
|
|
if (node) {
|
|
node->setProperty(property, value, comment, defValue);
|
|
bool hidden = prop->isHidden();
|
|
if (node == m_nodes[hidden][ConfigProperty::NO_SHARING].get() &&
|
|
(node = m_nodes[hidden][ConfigProperty::SOURCE_SET_SHARING].get()) != NULL &&
|
|
(prop->getFlags() & ConfigProperty::SHARED_AND_UNSHARED)) {
|
|
node->setProperty(property, value, comment, defValue);
|
|
}
|
|
} else {
|
|
SE_THROW(property + ": not supported by configuration multiplexer");
|
|
}
|
|
}
|
|
|
|
void MultiplexConfigNode::readProperties(PropsType &props) const
|
|
{
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e]) {
|
|
m_nodes[i][e]->readProperties(props);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MultiplexConfigNode::removeProperty(const string &property)
|
|
{
|
|
#if 1
|
|
SE_THROW(property + ": removing via configuration multiplexer not supported");
|
|
#else
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e]) {
|
|
m_nodes[i][e]->removeProperty(property);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void MultiplexConfigNode::clear()
|
|
{
|
|
#if 1
|
|
SE_THROW("configuration multiplexer cannot be cleared");
|
|
#else
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e]) {
|
|
m_nodes[i][e]->clear();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool MultiplexConfigNode::exists() const
|
|
{
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int e = 0; e < 3; e++) {
|
|
if (m_nodes[i][e] &&
|
|
m_nodes[i][e]->exists()) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
SE_END_CXX
|