From 2b99b57799477067d28654fe4df2462b07746b41 Mon Sep 17 00:00:00 2001 From: Patrick Ohly Date: Fri, 28 Jun 2013 11:45:55 +0000 Subject: [PATCH] Imported Upstream version 1.2.99~20120606~SE~ff65aef~SYSYNC~2728cb4 --- Makefile.in | 40 +- README | 4 +- configure | 20 +- .../activesync/ActiveSyncSourceRegister.cpp | 36 +- src/backends/activesync/README | 25 +- src/backends/evolution/EvolutionCalendarSource.cpp | 63 +- src/backends/evolution/EvolutionContactSource.cpp | 48 +- src/backends/evolution/EvolutionSyncSource.h | 4 + src/backends/kde/KDEPlatform.cpp | 9 +- src/backends/webdav/WebDAVSourceRegister.cpp | 4 +- src/client-test-app.cpp | 10 +- src/dbus/server/main.cpp | 1 - src/dbus/server/read-operations.cpp | 4 +- src/dbus/server/server.cpp | 1 + src/dbus/server/session-helper.cpp | 4 +- src/dbus/server/session.cpp | 6 +- src/syncevo/Cmdline.cpp | 110 ++- src/syncevo/ConfigFilter.cpp | 16 +- src/syncevo/ConfigFilter.h | 8 +- src/syncevo/ConfigNode.cpp | 10 +- src/syncevo/ConfigNode.h | 85 +- src/syncevo/DBusTraits.h | 30 +- src/syncevo/DevNullConfigNode.h | 9 +- src/syncevo/FileConfigNode.cpp | 421 ---------- src/syncevo/FileConfigNode.h | 143 ---- src/syncevo/FileConfigTree.cpp | 6 +- src/syncevo/FilterConfigNode.cpp | 23 +- src/syncevo/FilterConfigNode.h | 11 +- src/syncevo/IniConfigNode.cpp | 45 +- src/syncevo/IniConfigNode.h | 21 +- src/syncevo/MultiplexConfigNode.cpp | 15 +- src/syncevo/MultiplexConfigNode.h | 11 +- src/syncevo/PrefixConfigNode.cpp | 16 +- src/syncevo/PrefixConfigNode.h | 9 +- src/syncevo/SafeConfigNode.cpp | 19 +- src/syncevo/SafeConfigNode.h | 9 +- src/syncevo/SingleFileConfigTree.cpp | 16 +- src/syncevo/SyncConfig.cpp | 56 +- src/syncevo/SyncConfig.h | 64 +- src/syncevo/SyncContext.cpp | 70 +- src/syncevo/SyncContext.h | 4 +- src/syncevo/SyncSource.cpp | 4 +- src/syncevo/VolatileConfigNode.h | 7 +- src/syncevo/syncevo.am | 4 - src/syncevo/util.h | 4 + src/synthesis/ChangeLog | 853 ++++++++++++--------- src/synthesis/src/sysync/localengineds.cpp | 43 +- src/synthesis/src/sysync/syncsession.cpp | 35 + src/synthesis/src/sysync/syncsession.h | 2 + test/ClientTest.cpp | 28 +- test/synccompare.pl | 17 +- 51 files changed, 1163 insertions(+), 1340 deletions(-) delete mode 100644 src/syncevo/FileConfigNode.cpp delete mode 100644 src/syncevo/FileConfigNode.h diff --git a/Makefile.in b/Makefile.in index e272885..2e3f360 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1062,8 +1062,7 @@ am__src_syncevo_libsyncevolution_la_SOURCES_DIST = \ src/syncevo/FilterConfigNode.h \ src/syncevo/FilterConfigNode.cpp src/syncevo/SafeConfigNode.h \ src/syncevo/SafeConfigNode.cpp src/syncevo/PrefixConfigNode.h \ - src/syncevo/PrefixConfigNode.cpp src/syncevo/FileConfigNode.h \ - src/syncevo/FileConfigNode.cpp src/syncevo/IniConfigNode.h \ + src/syncevo/PrefixConfigNode.cpp src/syncevo/IniConfigNode.h \ src/syncevo/IniConfigNode.cpp \ src/syncevo/SingleFileConfigTree.h \ src/syncevo/SingleFileConfigTree.cpp src/syncevo/DataBlob.h \ @@ -1107,7 +1106,6 @@ am__src_syncevo_libsyncevolution_la_SOURCES_DIST = \ @COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-FilterConfigNode.lo \ @COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-SafeConfigNode.lo \ @COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-PrefixConfigNode.lo \ -@COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo \ @COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-IniConfigNode.lo \ @COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-SingleFileConfigTree.lo \ @COND_CORE_TRUE@ src/syncevo/src_syncevo_libsyncevolution_la-FileDataBlob.lo \ @@ -1859,16 +1857,15 @@ am__src_syncevo_libsyncevolution_include_HEADERS_DIST = \ src/syncevo/ConfigFilter.h src/syncevo/GLibSupport.h \ src/syncevo/TrackingSyncSource.h src/syncevo/MapSyncSource.h \ src/syncevo/LogRedirect.h src/syncevo/LogStdout.h \ - src/syncevo/LogSyslog.h src/syncevo/FileConfigNode.h \ - src/syncevo/FilterConfigNode.h src/syncevo/PrefixConfigNode.h \ - src/syncevo/SafeConfigNode.h src/syncevo/SyncConfig.h \ - src/syncevo/SyncSource.h src/syncevo/util.h \ - src/syncevo/SuspendFlags.h src/syncevo/SyncContext.h \ - src/syncevo/Timespec.h src/syncevo/UserInterface.h \ - src/syncevo/SynthesisEngine.h src/syncevo/Logging.h \ - src/syncevo/SyncML.h src/syncevo/eds_abi_wrapper.h \ - src/syncevo/icalstrdup.h src/syncevo/SmartPtr.h \ - src/syncevo/ConfigNode.h + src/syncevo/LogSyslog.h src/syncevo/FilterConfigNode.h \ + src/syncevo/PrefixConfigNode.h src/syncevo/SafeConfigNode.h \ + src/syncevo/SyncConfig.h src/syncevo/SyncSource.h \ + src/syncevo/util.h src/syncevo/SuspendFlags.h \ + src/syncevo/SyncContext.h src/syncevo/Timespec.h \ + src/syncevo/UserInterface.h src/syncevo/SynthesisEngine.h \ + src/syncevo/Logging.h src/syncevo/SyncML.h \ + src/syncevo/eds_abi_wrapper.h src/syncevo/icalstrdup.h \ + src/syncevo/SmartPtr.h src/syncevo/ConfigNode.h HEADERS = $(nodist_src_dbus_qt_libsyncevolution_qt_dbus_include_HEADERS) \ $(src_dbus_glib_libsyncevo_dbus_include_HEADERS) \ $(src_syncevo_libsyncevolution_include_HEADERS) @@ -2467,8 +2464,6 @@ src_cppflags = -I$(top_srcdir)/src $(am__append_3) $(am__append_8) \ @COND_CORE_TRUE@ src/syncevo/SafeConfigNode.cpp \ @COND_CORE_TRUE@ src/syncevo/PrefixConfigNode.h \ @COND_CORE_TRUE@ src/syncevo/PrefixConfigNode.cpp \ -@COND_CORE_TRUE@ src/syncevo/FileConfigNode.h \ -@COND_CORE_TRUE@ src/syncevo/FileConfigNode.cpp \ @COND_CORE_TRUE@ src/syncevo/IniConfigNode.h \ @COND_CORE_TRUE@ src/syncevo/IniConfigNode.cpp \ @COND_CORE_TRUE@ src/syncevo/SingleFileConfigTree.h \ @@ -2498,7 +2493,6 @@ src_cppflags = -I$(top_srcdir)/src $(am__append_3) $(am__append_8) \ @COND_CORE_TRUE@ src/syncevo/LogRedirect.h \ @COND_CORE_TRUE@ src/syncevo/LogStdout.h \ @COND_CORE_TRUE@ src/syncevo/LogSyslog.h \ -@COND_CORE_TRUE@ src/syncevo/FileConfigNode.h \ @COND_CORE_TRUE@ \ @COND_CORE_TRUE@ src/syncevo/FilterConfigNode.h \ @COND_CORE_TRUE@ src/syncevo/PrefixConfigNode.h \ @@ -4256,9 +4250,6 @@ src/syncevo/src_syncevo_libsyncevolution_la-SafeConfigNode.lo: \ src/syncevo/src_syncevo_libsyncevolution_la-PrefixConfigNode.lo: \ src/syncevo/$(am__dirstamp) \ src/syncevo/$(DEPDIR)/$(am__dirstamp) -src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo: \ - src/syncevo/$(am__dirstamp) \ - src/syncevo/$(DEPDIR)/$(am__dirstamp) src/syncevo/src_syncevo_libsyncevolution_la-IniConfigNode.lo: \ src/syncevo/$(am__dirstamp) \ src/syncevo/$(DEPDIR)/$(am__dirstamp) @@ -5213,8 +5204,6 @@ mostlyclean-compile: -rm -f src/syncevo/src_syncevo_libsyncevolution_la-ConfigNode.lo -rm -f src/syncevo/src_syncevo_libsyncevolution_la-CurlTransportAgent.$(OBJEXT) -rm -f src/syncevo/src_syncevo_libsyncevolution_la-CurlTransportAgent.lo - -rm -f src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.$(OBJEXT) - -rm -f src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo -rm -f src/syncevo/src_syncevo_libsyncevolution_la-FileConfigTree.$(OBJEXT) -rm -f src/syncevo/src_syncevo_libsyncevolution_la-FileConfigTree.lo -rm -f src/syncevo/src_syncevo_libsyncevolution_la-FileDataBlob.$(OBJEXT) @@ -5482,7 +5471,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-ConfigFilter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-ConfigNode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-CurlTransportAgent.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FileConfigNode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FileConfigTree.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FileDataBlob.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FilterConfigNode.Plo@am__quote@ @@ -6927,14 +6915,6 @@ src/syncevo/src_syncevo_libsyncevolution_la-PrefixConfigNode.lo: src/syncevo/Pre @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_syncevo_libsyncevolution_la_CPPFLAGS) $(CPPFLAGS) $(src_syncevo_libsyncevolution_la_CXXFLAGS) $(CXXFLAGS) -c -o src/syncevo/src_syncevo_libsyncevolution_la-PrefixConfigNode.lo `test -f 'src/syncevo/PrefixConfigNode.cpp' || echo '$(srcdir)/'`src/syncevo/PrefixConfigNode.cpp -src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo: src/syncevo/FileConfigNode.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_syncevo_libsyncevolution_la_CPPFLAGS) $(CPPFLAGS) $(src_syncevo_libsyncevolution_la_CXXFLAGS) $(CXXFLAGS) -MT src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo -MD -MP -MF src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FileConfigNode.Tpo -c -o src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo `test -f 'src/syncevo/FileConfigNode.cpp' || echo '$(srcdir)/'`src/syncevo/FileConfigNode.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FileConfigNode.Tpo src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-FileConfigNode.Plo -@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='src/syncevo/FileConfigNode.cpp' object='src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_syncevo_libsyncevolution_la_CPPFLAGS) $(CPPFLAGS) $(src_syncevo_libsyncevolution_la_CXXFLAGS) $(CXXFLAGS) -c -o src/syncevo/src_syncevo_libsyncevolution_la-FileConfigNode.lo `test -f 'src/syncevo/FileConfigNode.cpp' || echo '$(srcdir)/'`src/syncevo/FileConfigNode.cpp - src/syncevo/src_syncevo_libsyncevolution_la-IniConfigNode.lo: src/syncevo/IniConfigNode.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(src_syncevo_libsyncevolution_la_CPPFLAGS) $(CPPFLAGS) $(src_syncevo_libsyncevolution_la_CXXFLAGS) $(CXXFLAGS) -MT src/syncevo/src_syncevo_libsyncevolution_la-IniConfigNode.lo -MD -MP -MF src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-IniConfigNode.Tpo -c -o src/syncevo/src_syncevo_libsyncevolution_la-IniConfigNode.lo `test -f 'src/syncevo/IniConfigNode.cpp' || echo '$(srcdir)/'`src/syncevo/IniConfigNode.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-IniConfigNode.Tpo src/syncevo/$(DEPDIR)/src_syncevo_libsyncevolution_la-IniConfigNode.Plo diff --git a/README b/README index 0ae1f14..e00a36e 100644 --- a/README +++ b/README @@ -7,8 +7,8 @@ synchronize personal information management data ------------------------------------------------ :Manual section: 1 -:Version: 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2 -:Date: 2012-05-30 +:Version: 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4 +:Date: 2012-06-06 SYNOPSIS diff --git a/configure b/configure index 2f1b9ca..42a5c0f 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for syncevolution 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2. +# Generated by GNU Autoconf 2.65 for syncevolution 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -698,8 +698,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='syncevolution' PACKAGE_TARNAME='syncevolution' -PACKAGE_VERSION='1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2' -PACKAGE_STRING='syncevolution 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2' +PACKAGE_VERSION='1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4' +PACKAGE_STRING='syncevolution 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1783,7 +1783,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures syncevolution 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2 to adapt to many kinds of systems. +\`configure' configures syncevolution 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1853,7 +1853,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of syncevolution 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2:";; + short | recursive ) echo "Configuration of syncevolution 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4:";; esac cat <<\_ACEOF @@ -2245,7 +2245,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -syncevolution configure 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2 +syncevolution configure 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4 generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. @@ -2818,7 +2818,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by syncevolution $as_me 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2, which was +It was created by syncevolution $as_me 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -3704,7 +3704,7 @@ fi # Define the identity of the package. PACKAGE='syncevolution' - VERSION='1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2' + VERSION='1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4' cat >>confdefs.h <<_ACEOF @@ -24099,7 +24099,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by syncevolution $as_me 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2, which was +This file was extended by syncevolution $as_me 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -24165,7 +24165,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -syncevolution config.status 1.2.99+20120530+SE+48b6fef+SYSYNC+2d7d1b2 +syncevolution config.status 1.2.99+20120606+SE+ff65aef+SYSYNC+2728cb4 configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" diff --git a/src/backends/activesync/ActiveSyncSourceRegister.cpp b/src/backends/activesync/ActiveSyncSourceRegister.cpp index 31fa68c..e4377ac 100644 --- a/src/backends/activesync/ActiveSyncSourceRegister.cpp +++ b/src/backends/activesync/ActiveSyncSourceRegister.cpp @@ -142,7 +142,8 @@ namespace { * operation. Using the cached information implies that we won't find bugs in * the handling of that information. */ -static int DumpItems(ClientTest &client, TestingSyncSource &source, const std::string &file) +static int DumpItems(ClientTest &client, TestingSyncSource &source, const std::string &file, + bool forceBaseReadItem) { ActiveSyncSource &eassource = static_cast(source); ofstream out(file.c_str()); @@ -161,7 +162,20 @@ static int DumpItems(ClientTest &client, TestingSyncSource &source, const std::s BOOST_FOREACH(const std::string &easid, easids) { std::string item; - eassource.ActiveSyncSource::readItem(easid, item); + if (forceBaseReadItem) { + // This bypasses the more specialized + // ActiveSyncCalendarSource::readItem(), which helps + // reveal potential bugs in it. However, it depends on a + // working Fetch operation in the ActiveSync server, which + // Google doesn't seem to provide (404 error). + eassource.ActiveSyncSource::readItem(easid, item); + } else { + // Normal readItem() works with Google by using the cached + // item. However, the source must have done a beginSync() + // with empty sync key, because otherwise the cache is + // not guaranteed to be complete. + eassource.readItem(easid, item); + } out << item << '\n'; if (!boost::ends_with(item, "\n")) { out << '\n'; @@ -201,7 +215,8 @@ static TestingSyncSource *createEASSource(const ClientTestConfig::createsource_t // common settings for all kinds of data static void updateConfigEAS(const RegisterSyncSourceTest */* me */, - ClientTestConfig &config) + ClientTestConfig &config, + EasItemType type) { // cannot run tests involving a second database: // wrap orginal source creation, set default database for @@ -211,7 +226,12 @@ static void updateConfigEAS(const RegisterSyncSourceTest */* me */, config.m_createSourceB = boost::bind(createEASSource, config.m_createSourceB, _1, _2, _3, _4); - config.m_dump = DumpItems; + config.m_dump = boost::bind(DumpItems, _1, _2, _3, + type == EAS_ITEM_CONTACT || + // need to read from our cache for Google Calendar, + // because it does not support Fetch + strcmp(getEnv("CLIENT_TEST_SERVER", ""), "googleeas") + ); config.m_sourceLUIDsAreVolatile = true; // TODO: find out how ActiveSync/Exchange handle children without parent; // at the moment, the child is stored as if it was a stand-alone event @@ -233,7 +253,7 @@ public: // TODO: provide comprehensive set of vCard 3.0 contacts as they are understood by the ActiveSync library // config.testcases = "testcases/eas_contact.vcf"; - updateConfigEAS(this, config); + updateConfigEAS(this, config, EAS_ITEM_CONTACT); } } ActiveSyncContactTest; @@ -246,7 +266,7 @@ public: virtual void updateConfig(ClientTestConfig &config) const { config.m_type = "eas-events"; - updateConfigEAS(this, config); + updateConfigEAS(this, config, EAS_ITEM_CALENDAR); } } ActiveSyncEventTest; @@ -259,7 +279,7 @@ public: virtual void updateConfig(ClientTestConfig &config) const { config.m_type = "eas-todos"; - updateConfigEAS(this, config); + updateConfigEAS(this, config, EAS_ITEM_TODO); } } ActiveSyncTodoTest; @@ -272,7 +292,7 @@ public: virtual void updateConfig(ClientTestConfig &config) const { config.m_type = "eas-memos"; - updateConfigEAS(this, config); + updateConfigEAS(this, config, EAS_ITEM_JOURNAL); } } ActiveSyncMemoTest; diff --git a/src/backends/activesync/README b/src/backends/activesync/README index 6674730..be50f57 100644 --- a/src/backends/activesync/README +++ b/src/backends/activesync/README @@ -74,6 +74,10 @@ which must simulate two independent ActiveSync clients. Configure "local" testing (backend is covered, no syncing involved): ./syncevolution --configure username= \ + eas_event/backend=eas-events \ + eas_event/database= \ + eas_contact/backend=eas-contacts \ + eas_contact/database= \ --template SyncEvolution target-config@client-test-exchange On MeeGo: @@ -114,19 +118,22 @@ Sync Testing syncevolution --configure \ syncURL=local://@exchange \ username= \ - backend=evolution-calendar \ eds_event/backend=evolution-calendar \ - eds_event/uri=calendar \ + eds_event/uri=eas_event \ + eds_event/database=SyncEvolution_Test_eds_event_1 \ eds_contact/backend=evolution-contacts \ - eds_contact/uri=addressbook \ + eds_contact/uri=eas_contact \ + eds_contact/database=SyncEvolution_Test_eds_contact_1 \ --template SyncEvolution_Client exchange_1@client-test-1 eds_event eds_contact syncevolution --configure \ syncURL=local://@exchange \ username=_B \ eds_event/backend=evolution-calendar \ - eds_event/uri=calendar \ + eds_event/uri=eas_event \ + eds_event/database=SyncEvolution_Test_eds_event_2 \ eds_contact/backend=evolution-contacts \ - eds_contact/uri=addressbook \ + eds_contact/uri=eas_contact \ + eds_contact/database=SyncEvolution_Test_eds_contact_2 \ --template SyncEvolution_Client exchange_2@client-test-2 eds_event eds_contact - Create calendars named as follows in Evolution: SyncEvolution_Test_eds_event_1 @@ -140,3 +147,11 @@ target-config@exchange with different usernames in each sync config. This is necessary because change tracking depends on that username. + +Google via ActiveSync +===================== + +- Use "googleeas" instead of "exchange", because ActiveSyncSourceRegister.cpp + needs to know that it is talking to Google, to work around the lack of + Fetch command support. + diff --git a/src/backends/evolution/EvolutionCalendarSource.cpp b/src/backends/evolution/EvolutionCalendarSource.cpp index d6573e5..90b5d69 100644 --- a/src/backends/evolution/EvolutionCalendarSource.cpp +++ b/src/backends/evolution/EvolutionCalendarSource.cpp @@ -135,25 +135,26 @@ EvolutionCalendarSource::EvolutionCalendarSource(EvolutionCalendarSourceType typ SyncSource::Databases EvolutionCalendarSource::getDatabases() { - ESourceList *sources = NULL; + ESourceList *tmp = NULL; GErrorCXX gerror; Databases result; if ( #ifdef USE_ECAL_CLIENT - !e_cal_client_get_sources(&sources, sourceType(), gerror) + !e_cal_client_get_sources(&tmp, sourceType(), gerror) #else - !e_cal_get_sources(&sources, sourceType(), gerror) + !e_cal_get_sources(&tmp, sourceType(), gerror) #endif ) { // ignore unspecific errors (like on Maemo with no support for memos) // and continue with empty list (perhaps defaults work) if (!gerror) { - sources = NULL; + tmp = NULL; } else { throwError("unable to access backend databases", gerror); } } + ESourceListCXX sources(tmp, false); bool first = true; for (GSList *g = sources ? e_source_list_peek_groups (sources) : NULL; @@ -237,7 +238,7 @@ char *EvolutionCalendarSource::authenticate(const char *prompt, void EvolutionCalendarSource::open() { - ESourceList *sources; + ESourceList *tmp; GErrorCXX gerror; bool onlyIfExists = false; // always try to create address book, because even if there is // a source there's no guarantee that the actual database was @@ -246,9 +247,10 @@ void EvolutionCalendarSource::open() // therefore failed in some cases #ifdef USE_ECAL_CLIENT - if (!e_cal_client_get_sources (&sources, sourceType(), gerror)) { - gerror.throwError("unable to access backend databases"); + if (!e_cal_client_get_sources (&tmp, sourceType(), gerror)) { + throwError("unable to access backend databases", gerror); } + ESourceListCXX sources(tmp, false); string id = getDatabaseID(); ESource *source = findSource(sources, id); @@ -279,7 +281,7 @@ void EvolutionCalendarSource::open() } if (gerror) { - gerror.throwError("create calendar"); + throwError("create calendar", gerror); } // Listen for errors @@ -294,17 +296,18 @@ void EvolutionCalendarSource::open() gerror.clear(); sleep(5); if (!e_client_open_sync(E_CLIENT ((ECalClient*)m_calendar), onlyIfExists, NULL, gerror)) { - gerror.throwError(string("opening ") + m_typeName ); + throwError(string("opening ") + m_typeName , gerror); } } else { - gerror.throwError(string("opening ") + m_typeName ); + throwError(string("opening ") + m_typeName , gerror); } } } #else - if (!e_cal_get_sources(&sources, sourceType(), gerror)) { + if (!e_cal_get_sources(&tmp, sourceType(), gerror)) { throwError("unable to access backend databases", gerror); } + ESourceListCXX sources(tmp, false); string id = getDatabaseID(); ESource *source = findSource(sources, id); @@ -454,7 +457,7 @@ void EvolutionCalendarSource::listAllItems(RevisionMap_t &revisions) ECalClientView *view; if (!e_cal_client_get_view_sync (m_calendar, "#t", &view, NULL, gerror)) { - gerror.throwError( "getting the view" ); + throwError( "getting the view" , gerror); } ECalClientViewCXX viewPtr = ECalClientViewCXX::steal(view); @@ -462,7 +465,7 @@ void EvolutionCalendarSource::listAllItems(RevisionMap_t &revisions) ECalClientViewSyncHandler handler(viewPtr, list_revisions, &revisions); if (!handler.processSync(gerror)) { - gerror.throwError("watching view"); + throwError("watching view", gerror); } // Update m_allLUIDs @@ -506,6 +509,32 @@ void EvolutionCalendarSource::readItem(const string &luid, std::string &item, bo item = retrieveItemAsString(id); } +#ifdef USE_ECAL_CLIENT +icaltimezone * +my_tzlookup(const gchar *tzid, + gconstpointer ecalclient, + GCancellable *cancellable, + GError **error) +{ + icaltimezone *zone = NULL; + GError *local_error = NULL; + + if (e_cal_client_get_timezone_sync((ECalClient *)ecalclient, tzid, &zone, cancellable, &local_error)) { + return zone; + } else if (local_error && local_error->domain == E_CAL_CLIENT_ERROR) { + // Ignore *all* E_CAL_CLIENT_ERROR errors, e_cal_client_get_timezone_sync() does + // not reliably return a specific code like E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND. + // See the 'e_cal_client_check_timezones() + e_cal_client_tzlookup() + Could not retrieve calendar time zone: Invalid object' + // mail thread. + g_clear_error (&local_error); + } else if (local_error) { + g_propagate_error (error, local_error); + } + + return NULL; +} +#endif + EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(const string &luid, const std::string &item, bool raw) { bool update = !luid.empty(); @@ -558,7 +587,7 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co #ifdef USE_ECAL_CLIENT !e_cal_client_check_timezones(icomp, NULL, - e_cal_client_tzlookup, + my_tzlookup, (const void *)m_calendar.get(), NULL, gerror) @@ -777,6 +806,9 @@ EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(co ) { throwError(string("creating updated item ") + luid, gerror); } +#ifdef USE_ECAL_CLIENT + PlainGStr owner((gchar *)uid); +#endif // Recreate any children removed earlier: when we get here, // the parent exists and we must update it. @@ -914,6 +946,9 @@ void EvolutionCalendarSource::removeItem(const string &luid) ) { throwError(string("recreating first item ") + luid, gerror); } +#ifdef USE_ECAL_CLIENT + PlainGStr owner((gchar *)uid); +#endif first = false; } else { if ( diff --git a/src/backends/evolution/EvolutionContactSource.cpp b/src/backends/evolution/EvolutionContactSource.cpp index f1bd911..bcb648b 100644 --- a/src/backends/evolution/EvolutionContactSource.cpp +++ b/src/backends/evolution/EvolutionContactSource.cpp @@ -194,18 +194,22 @@ handle_authentication_cb (EClient */*client*/, ECredentials *credentials, gpoint void EvolutionContactSource::open() { + GErrorCXX gerror; + bool created = false; + bool onlyIfExists = false; // always try to create address book, because even if there is + // a source there's no guarantee that the actual database was + // created already; the original logic below for only setting + // this when explicitly requesting a new address book + // therefore failed in some cases #ifdef USE_EBOOK_CLIENT - ESourceList *sources; - - if (!e_book_client_get_sources(&sources, NULL)) { - throwError("unable to access address books"); + ESourceList *tmp; + if (!e_book_client_get_sources(&tmp, gerror)) { + throwError("unable to access address books", gerror); } - + ESourceListCXX sources(tmp, false); + string id = getDatabaseID(); ESource *source = findSource(sources, id); - bool onlyIfExists = true; - bool created = false; - GErrorCXX gerror; if (!source) { // might have been special "<>" or "<>", try that and // creating address book from file:// URI before giving up @@ -219,13 +223,12 @@ void EvolutionContactSource::open() throwError(string(getName()) + ": no such address book: '" + id + "'"); } created = true; - onlyIfExists = false; } else { m_addressbook = EBookClientCXX::steal(e_book_client_new( source, gerror )); } if (gerror) { - gerror.throwError("create addressbook"); + throwError("create addressbook", gerror); } // Listen for errors @@ -241,10 +244,10 @@ void EvolutionContactSource::open() gerror.clear(); sleep(5); if (!e_client_open_sync( E_CLIENT ((EBookClient*)m_addressbook), onlyIfExists, NULL, gerror)) { - gerror.throwError("opening address book"); + throwError("opening address book", gerror); } } else { - gerror.throwError("opening address book"); + throwError("opening address book", gerror); } } @@ -253,20 +256,14 @@ void EvolutionContactSource::open() G_CALLBACK(SyncContext::fatalError), (void *)"Evolution Data Server has died unexpectedly, contacts no longer available."); #else - ESourceList *sources; - if (!e_book_get_addressbooks(&sources, NULL)) { - throwError("unable to access address books"); + ESourceList *tmp; + if (!e_book_get_addressbooks(&tmp, gerror)) { + throwError("unable to access address books", gerror); } - - GErrorCXX gerror; + ESourceListCXX sources(tmp, false); + string id = getDatabaseID(); ESource *source = findSource(sources, id); - bool onlyIfExists = false; // always try to create address book, because even if there is - // a source there's no guarantee that the actual database was - // created already; the original logic below for only setting - // this when explicitly requesting a new address book - // therefore failed in some cases - bool created = false; if (!source) { // might have been special "<>" or "<>", try that and // creating address book from file:// URI before giving up @@ -280,7 +277,6 @@ void EvolutionContactSource::open() throwError(string(getName()) + ": no such address book: '" + id + "'"); } created = true; - onlyIfExists = false; } else { m_addressbook.set( e_book_new( source, gerror ), "address book" ); } @@ -444,7 +440,7 @@ void EvolutionContactSource::listAllItems(RevisionMap_t &revisions) PlainGStr sexp(e_book_query_to_string (allItemsQuery.get())); if (!e_book_client_get_view_sync(m_addressbook, sexp, &view, NULL, gerror)) { - gerror.throwError( "getting the view" ); + throwError( "getting the view" , gerror); } EBookClientViewCXX viewPtr = EBookClientViewCXX::steal(view); @@ -460,7 +456,7 @@ void EvolutionContactSource::listAllItems(RevisionMap_t &revisions) EBookClientViewSyncHandler handler(viewPtr, list_revisions, &revisions); if (!handler.process(gerror)) { - gerror.throwError("watching view"); + throwError("watching view", gerror); } #else GErrorCXX gerror; diff --git a/src/backends/evolution/EvolutionSyncSource.h b/src/backends/evolution/EvolutionSyncSource.h index 97c2650..7102474 100644 --- a/src/backends/evolution/EvolutionSyncSource.h +++ b/src/backends/evolution/EvolutionSyncSource.h @@ -27,6 +27,10 @@ #include #include +#ifdef HAVE_EDS +SE_GOBJECT_TYPE(ESourceList) +#endif + SE_BEGIN_CXX diff --git a/src/backends/kde/KDEPlatform.cpp b/src/backends/kde/KDEPlatform.cpp index 087ea67..1016dbf 100644 --- a/src/backends/kde/KDEPlatform.cpp +++ b/src/backends/kde/KDEPlatform.cpp @@ -24,6 +24,12 @@ #include "KDEPlatform.h" +#include +#include + +// Qt headers may define "signals" as preprocessor symbol, +// which conflicts with glib C headers included indirectly +// above. This order of header files works. #include #include #include @@ -36,9 +42,6 @@ #include -#include -#include - #include SE_BEGIN_CXX diff --git a/src/backends/webdav/WebDAVSourceRegister.cpp b/src/backends/webdav/WebDAVSourceRegister.cpp index 7ff679d..b5190fb 100644 --- a/src/backends/webdav/WebDAVSourceRegister.cpp +++ b/src/backends/webdav/WebDAVSourceRegister.cpp @@ -293,7 +293,7 @@ public: // Always set properties taken from the environment. - nodes.getProperties()->setProperty("backend", m_type); + nodes.getProperties()->setProperty("backend", InitStateString(m_type, true)); SE_LOG_DEBUG(NULL, NULL, " additional property backend = %s (from CLIENT_TEST_WEBDAV)", m_type.c_str()); BOOST_FOREACH(const StringPair &propval, m_props) { @@ -301,7 +301,7 @@ public: if (node) { SE_LOG_DEBUG(NULL, NULL, " additional property %s = %s (from CLIENT_TEST_WEBDAV)", propval.first.c_str(), propval.second.c_str()); - node->setProperty(propval.first, propval.second); + node->setProperty(propval.first, InitStateString(propval.second, true)); } else if (!boost::ends_with(propval.first, "testconfig") && !boost::ends_with(propval.first, "testcases")) { SE_THROW(StringPrintf("invalid property %s=%s set in CLIENT_TEST_WEBDAV for %s %s", diff --git a/src/client-test-app.cpp b/src/client-test-app.cpp index 6ebdad3..ab1b7a2 100644 --- a/src/client-test-app.cpp +++ b/src/client-test-app.cpp @@ -235,14 +235,14 @@ public: // but then no longer can be used to change the config. // This prevents accidentally running a test with default // values, for example for the database. - if (sc->getDatabaseID().empty()) { + if (!sc->getDatabaseID().wasSet()) { string database = getDatabaseName(test->m_configName); sc->setDatabaseID(database); } - if (sc->getUser().empty() && !m_evoUser.empty()) { + if (!sc->getUser().wasSet() && !m_evoUser.empty()) { sc->setUser(m_evoUser); } - if (sc->getPassword().empty() && !m_evoPassword.empty()) { + if (!sc->getPassword().wasSet() && !m_evoPassword.empty()) { sc->setPassword(m_evoPassword); } // Always set this one, to ensure the config matches the test. @@ -402,10 +402,10 @@ public: // configure active sources with the desired sync mode, // disable the rest FilterConfigNode::ConfigFilter filter; - filter["sync"] = "none"; + filter["sync"] = InitStateString("none", true); client.setConfigFilter(false, "", filter); filter["sync"] = - PrettyPrintSyncMode(options.m_syncMode); + InitStateString(PrettyPrintSyncMode(options.m_syncMode), true); for(int i = 0; sources[i] >= 0; i++) { std::string &name = m_syncSource2Config[sources[i]]; client.setConfigFilter(false, name, filter); diff --git a/src/dbus/server/main.cpp b/src/dbus/server/main.cpp index 9dc7b39..965821b 100644 --- a/src/dbus/server/main.cpp +++ b/src/dbus/server/main.cpp @@ -150,7 +150,6 @@ int main(int argc, char **argv, char **envp) unsetenv("G_DBUS_DEBUG"); } - SE_LOG_INFO(NULL, NULL, "ready to run"); server->run(); SE_LOG_DEBUG(NULL, NULL, "cleaning up"); server.reset(); diff --git a/src/dbus/server/read-operations.cpp b/src/dbus/server/read-operations.cpp index c5bf9a0..e7ad51b 100644 --- a/src/dbus/server/read-operations.cpp +++ b/src/dbus/server/read-operations.cpp @@ -22,6 +22,8 @@ #include "server.h" #include "dbus-sync.h" +#include + SE_BEGIN_CXX ReadOperations::ReadOperations(const std::string &config_name, Server &server) : @@ -268,7 +270,7 @@ void ReadOperations::getReports(uint32_t start, uint32_t count, } /** serialize report to ConfigProps and then copy them to reports */ - HashFileConfigNode node("/dev/null","",true); + IniHashConfigNode node("/dev/null","",true); node << report; ConfigProps props; node.readProperties(props); diff --git a/src/dbus/server/server.cpp b/src/dbus/server/server.cpp index f187bec..eac5279 100644 --- a/src/dbus/server/server.cpp +++ b/src/dbus/server/server.cpp @@ -386,6 +386,7 @@ void Server::run() } } + SE_LOG_INFO(NULL, NULL, "ready to run"); if (!m_shutdownRequested) { g_main_loop_run(m_loop); } diff --git a/src/dbus/server/session-helper.cpp b/src/dbus/server/session-helper.cpp index 052747b..1ce061f 100644 --- a/src/dbus/server/session-helper.cpp +++ b/src/dbus/server/session-helper.cpp @@ -187,12 +187,12 @@ bool SessionHelper::doRestore(const std::string &configName, if (!sources.empty()) { BOOST_FOREACH(const std::string &source, sources) { FilterConfigNode::ConfigFilter filter; - filter["sync"] = "two-way"; + filter["sync"] = InitStateString("two-way", true); sync.setConfigFilter(false, source, filter); } // disable other sources FilterConfigNode::ConfigFilter disabled; - disabled["sync"] = "disabled"; + disabled["sync"] = InitStateString("disabled", true); sync.setConfigFilter(false, "", disabled); } sync.restore(dir, diff --git a/src/dbus/server/session.cpp b/src/dbus/server/session.cpp index db25308..db5fe93 100644 --- a/src/dbus/server/session.cpp +++ b/src/dbus/server/session.cpp @@ -150,7 +150,7 @@ static void copyProperty(const StringPair &keyvalue, SE_THROW_EXCEPTION(InvalidCall, StringPrintf("invalid value '%s' for property '%s': '%s'", value.c_str(), name.c_str(), error.c_str())); } - filter.insert(keyvalue); + filter.insert(std::make_pair(keyvalue.first, InitStateString(keyvalue.second, true))); } static void setSyncFilters(const ReadOperations::Config_t &config,FilterConfigNode::ConfigFilter &syncFilter,std::map &sourceFilters) @@ -369,8 +369,8 @@ void Session::sync2(const std::string &mode, const SessionCommon::SourceModes_t boost::shared_ptr c = m_connection.lock(); if (c && !c->mustAuthenticate()) { // unsetting username/password disables checking them - params.m_syncFilter["password"] = ""; - params.m_syncFilter["username"] = ""; + params.m_syncFilter["password"] = InitStateString("", true); + params.m_syncFilter["username"] = InitStateString("", true); } // Relay messages between connection and helper.If the diff --git a/src/syncevo/Cmdline.cpp b/src/syncevo/Cmdline.cpp index 98ff8d5..31ba8eb 100644 --- a/src/syncevo/Cmdline.cpp +++ b/src/syncevo/Cmdline.cpp @@ -550,21 +550,21 @@ void Cmdline::finishCopy(const boost::shared_ptr &from, // Also disable auto-syncing in the migrated config. StringConfigProperty autosync("autoSync", "", ""); { - FileConfigNode node(from->getRootPath(), "config.ini", false); + IniFileConfigNode node(from->getRootPath(), "config.ini", false); if (ready.getPropertyValue(node)) { ready.setProperty(node, false); } if (!autosync.getProperty(node).empty()) { - autosync.setProperty(node, "0"); + autosync.setProperty(node, InitStateString("0", true)); } node.flush(); } // same for very old configs { - FileConfigNode node(from->getRootPath() + "/spds/syncml", "config.txt", false); + IniFileConfigNode node(from->getRootPath() + "/spds/syncml", "config.txt", false); if (!autosync.getProperty(node).empty()) { - autosync.setProperty(node, "0"); + autosync.setProperty(node, InitStateString("0", true)); } node.flush(); } @@ -1063,9 +1063,9 @@ bool Cmdline::run() { BOOST_FOREACH(const std::string source, from->getSyncSources()) { BOOST_FOREACH(const string &peer, peers) { - FileConfigNode node(from->getRootPath() + "/peers/" + peer + "/sources/" + source, - "config.ini", - true); + IniFileConfigNode node(from->getRootPath() + "/peers/" + peer + "/sources/" + source, + "config.ini", + true); string sync = node.readProperty("sync"); if (sync.empty() || boost::iequals(sync, "none") || @@ -1558,7 +1558,7 @@ bool Cmdline::run() { // temporarily disable the rest FilterConfigNode::ConfigFilter disabled; - disabled["sync"] = "disabled"; + disabled["sync"] = InitStateString("disabled", true); context->setConfigFilter(false, "", disabled); } @@ -1605,7 +1605,8 @@ bool Cmdline::run() { SyncContext::DATABASE_BEFORE_SYNC); } else { if (m_dryrun) { - SyncContext::throwError("--dry-run not supported for running a synchronization"); + usage(false, "--dry-run not supported for running a synchronization"); + return false; } // safety catch: if props are given, then --run @@ -1769,10 +1770,19 @@ bool Cmdline::parseProp(PropertyType propertyType, return false; } ContextProps &props = m_props[spec.m_config]; - props.m_sourceProps[spec.m_source]["backend"] = sourceType.m_backend; - props.m_sourceProps[spec.m_source]["databaseFormat"] = sourceType.m_localFormat; - props.m_sourceProps[spec.m_source]["syncFormat"] = sourceType.m_format; - props.m_sourceProps[spec.m_source]["forceSyncFormat"] = sourceType.m_forceFormat ? "1" : "0"; + props.m_sourceProps[spec.m_source]["backend"] = + InitStateString(sourceType.m_backend, + !sourceType.m_backend.empty()); + props.m_sourceProps[spec.m_source]["databaseFormat"] = + InitStateString(sourceType.m_localFormat, + !sourceType.m_localFormat.empty()); + props.m_sourceProps[spec.m_source]["syncFormat"] = + InitStateString(sourceType.m_format, + !sourceType.m_format.empty()); + props.m_sourceProps[spec.m_source]["forceSyncFormat"] = + sourceType.m_forceFormat ? + InitStateString("1", true) : + InitStateString("0", false); return true; } else if (!prop) { SE_LOG_ERROR(NULL, NULL, "%s: no such property", args.c_str()); @@ -3444,11 +3454,40 @@ protected: CPPUNIT_ASSERT_EQUAL(std::string("GNOME"), keyring.get()); } + // Broken command line: treated like a sync, but config doesn't exist. + { + TestCmdline cmdline("keyring=KDE", "@foobar", NULL); + cmdline.doit(false); + CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str()); + CPPUNIT_ASSERT_EQUAL(std::string("[INFO] Configuration \"@foobar\" does not refer to a sync peer.\n[ERROR] Cannot proceed with sync without a configuration."), cmdline.m_err.str()); + } + { + TestCmdline cmdline("keyring=KDE", "nosuchpeer@foobar", NULL); + cmdline.doit(false); + CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str()); + CPPUNIT_ASSERT_EQUAL(std::string("[INFO] Configuration \"nosuchpeer@foobar\" does not exist.\n[ERROR] Cannot proceed with sync without a configuration."), cmdline.m_err.str()); + } + // empty config prop { TestCmdline cmdline("--configure", "@default", NULL); cmdline.doit(); } + + // Try broken command line again. + { + TestCmdline cmdline("keyring=KDE", "@foobar", NULL); + cmdline.doit(false); + CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str()); + CPPUNIT_ASSERT_EQUAL(std::string("[INFO] Configuration \"@foobar\" does not refer to a sync peer.\n[ERROR] Cannot proceed with sync without a configuration."), cmdline.m_err.str()); + } + { + TestCmdline cmdline("keyring=KDE", "nosuchpeer@foobar", NULL); + cmdline.doit(false); + CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str()); + CPPUNIT_ASSERT_EQUAL(std::string("[INFO] Configuration \"nosuchpeer@foobar\" does not exist.\n[ERROR] Cannot proceed with sync without a configuration."), cmdline.m_err.str()); + } + { TestCmdline cmdline("@foobar", NULL); boost::shared_ptr context = cmdline.parse(); @@ -3462,9 +3501,6 @@ protected: { TestCmdline cmdline("--keyring", "--configure", "@default", NULL); cmdline.doit(); - } - { - TestCmdline cmdline("@foobar", NULL); boost::shared_ptr context = cmdline.parse(); CPPUNIT_ASSERT(context); InitStateTri keyring = context->getKeyring(); @@ -3474,15 +3510,34 @@ protected: { TestCmdline cmdline("--keyring=KDE", "--configure", "@default", NULL); cmdline.doit(); + boost::shared_ptr context = cmdline.parse(); + CPPUNIT_ASSERT(context); + InitStateTri keyring = context->getKeyring(); + CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet()); + CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_STRING, keyring.getValue()); + CPPUNIT_ASSERT_EQUAL(std::string("KDE"), keyring.get()); } + + // create by setting keyring in @default, then update; + // @default not strictly needed + rm_r(m_testDir); { - TestCmdline cmdline("@foobar", NULL); + TestCmdline cmdline("keyring=KDE", "--configure", "@default", NULL); + cmdline.doit(); boost::shared_ptr context = cmdline.parse(); CPPUNIT_ASSERT(context); InitStateTri keyring = context->getKeyring(); CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet()); CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_STRING, keyring.getValue()); - CPPUNIT_ASSERT_EQUAL(std::string("KDE"), keyring.get()); + } + { + TestCmdline cmdline("keyring=yes", "--configure", "@default", NULL); + cmdline.doit(); + boost::shared_ptr context = cmdline.parse(); + CPPUNIT_ASSERT(context); + InitStateTri keyring = context->getKeyring(); + CPPUNIT_ASSERT_EQUAL(true, keyring.wasSet()); + CPPUNIT_ASSERT_EQUAL(InitStateTri::VALUE_TRUE, keyring.getValue()); } // allow sync operation although --keyring was set @@ -3490,7 +3545,7 @@ protected: TestCmdline cmdline("keyring=GNOME", "foobar@default", NULL); cmdline.doit(false); CPPUNIT_ASSERT_EQUAL(std::string(""), cmdline.m_out.str()); - CPPUNIT_ASSERT_EQUAL(std::string("[ERROR] No configuration for server \"foobar@default\" found.\n[ERROR] cannot proceed without configuration"), cmdline.m_err.str()); + CPPUNIT_ASSERT_EQUAL(std::string("[INFO] Configuration \"foobar@default\" does not exist.\n[ERROR] Cannot proceed with sync without a configuration."), cmdline.m_err.str()); } // catch invalid "keyring" value @@ -3609,9 +3664,6 @@ protected: boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); - boost::replace_first(expected, - "# forceSyncFormat = 0", - "forceSyncFormat = 0"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, filterConfig(printConfig("scheduleworld"))); string shared = filterConfig(printConfig("@default")); @@ -4178,9 +4230,8 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - // migrating "type" sets forceSyncFormat (always) + // migrating "type" sets forceSyncFormat if not the default, // and databaseFormat (if format was part of type, as for addressbook) - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); doConfigure(expected, "sources/addressbook/config.ini:"); } @@ -4295,9 +4346,8 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - // migrating "type" sets forceSyncFormat (always) + // migrating "type" sets forceSyncFormat if different from the "false" default // and databaseFormat (if format was part of type, as for addressbook) - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, migratedConfig); string renamedConfig = scanFiles(oldRoot + ".old"); @@ -4330,7 +4380,6 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, migratedConfig); string renamedConfig = scanFiles(newRoot, "scheduleworld.old.1"); @@ -4363,7 +4412,6 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); boost::replace_first(expected, "peers/scheduleworld/sources/addressbook/config.ini", @@ -4403,7 +4451,6 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, migratedConfig); string renamedConfig = scanFiles(oldRoot + ".old"); @@ -4431,7 +4478,6 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, migratedConfig); renamedConfig = scanFiles(otherRoot, "scheduleworld.old.3"); @@ -4597,9 +4643,8 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - // migrating "type" sets forceSyncFormat (always) + // migrating "type" sets forceSyncFormat if not already the default, // and databaseFormat (if format was part of type, as for addressbook) - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, migratedConfig); string renamedConfig = scanFiles(oldRoot + ".old"); @@ -4627,7 +4672,6 @@ protected: boost::replace_first(expected, "# database = ", "database = xyz"); boost::replace_first(expected, "# databaseUser = ", "databaseUser = foo"); boost::replace_first(expected, "# databasePassword = ", "databasePassword = bar"); - boost::replace_all(expected, "# forceSyncFormat = 0", "forceSyncFormat = 0"); boost::replace_first(expected, "# databaseFormat = ", "databaseFormat = text/vcard"); CPPUNIT_ASSERT_EQUAL_DIFF(expected, migratedConfig); string renamedConfig = scanFiles(newRoot, "scheduleworld.old.1"); diff --git a/src/syncevo/ConfigFilter.cpp b/src/syncevo/ConfigFilter.cpp index fe40a32..9c7203c 100644 --- a/src/syncevo/ConfigFilter.cpp +++ b/src/syncevo/ConfigFilter.cpp @@ -29,7 +29,7 @@ SE_BEGIN_CXX void ConfigProps::add(const ConfigProps &other) { - BOOST_FOREACH(const StringPair &entry, other) { + BOOST_FOREACH(const ConfigProps::value_type &entry, other) { std::pair res = insert(entry); if (!res.second) { res.first->second = entry.second; @@ -37,16 +37,26 @@ void ConfigProps::add(const ConfigProps &other) } } -string ConfigProps::get(const string &key, const string &def) const +InitStateString ConfigProps::get(const string &key, const string &def) const { const_iterator it = find(key); if (it == end()) { - return def; + return InitStateString(def, false); } else { return it->second; } } +ConfigProps::operator string () const +{ + vector res; + BOOST_FOREACH(const StringPair &filter, *this) { + res.push_back(filter.first + " = " + filter.second); + } + sort(res.begin(), res.end()); + return boost::join(res, "\n"); +} + ConfigProps SourceProps::createSourceFilter(const std::string &source) const { const_iterator it = find(""); diff --git a/src/syncevo/ConfigFilter.h b/src/syncevo/ConfigFilter.h index 8c73ea8..b38ad81 100644 --- a/src/syncevo/ConfigFilter.h +++ b/src/syncevo/ConfigFilter.h @@ -28,8 +28,8 @@ #include SE_BEGIN_CXX -/** a case-insensitive string to string mapping */ -class ConfigProps : public std::map > { +/** a case-insensitive string to InitStateString mapping */ +class ConfigProps : public std::map > { public: /** format as = lines */ operator std::string () const; @@ -42,9 +42,9 @@ class ConfigProps : public std::map +#include #include #include @@ -32,11 +32,11 @@ boost::shared_ptr ConfigNode::createFileNode(const string &filename) string::size_type off = filename.rfind('/'); boost::shared_ptr filenode; if (off != filename.npos) { - filenode.reset(new FileConfigNode(filename.substr(0, off), - filename.substr(off + 1), - false)); + filenode.reset(new IniFileConfigNode(filename.substr(0, off), + filename.substr(off + 1), + false)); } else { - filenode.reset(new FileConfigNode(".", filename, false)); + filenode.reset(new IniFileConfigNode(".", filename, false)); } boost::shared_ptr savenode(new SafeConfigNode(filenode)); savenode->setMode(false); diff --git a/src/syncevo/ConfigNode.h b/src/syncevo/ConfigNode.h index 0243f10..07d34d3 100644 --- a/src/syncevo/ConfigNode.h +++ b/src/syncevo/ConfigNode.h @@ -65,33 +65,50 @@ class ConfigNode { * Returns the value of the given property * * @param property - the property name - * @return value of the property or empty string if not set + * @return value of the property or empty string if not set; + * also includes whether the property was set */ - virtual std::string readProperty(const std::string &property) const = 0; + virtual InitStateString readProperty(const std::string &property) const = 0; /** - * Sets a property value. + * Sets a property value. Overloaded, with variations providing + * convenience wrappers around it. * * @param property the property name - * @param value the property value (zero terminated string) + * @param value the property value and whether it is considered + * "explicitly set"; if it is not, then the property + * shall be removed from the list of properties * @param comment a comment explaining what the property is about, with * \n separating lines; might be used by the backend * when adding a new property - * @param defValue If a defValue is provided and the value - * matches the default, then the node is asked to - * remember that the value hasn't really been changed. - * An implementation can decide to not support this. + * @param defValue Default value in case that value isn't set. + * Can be be used by an implementation to annotate + * unset properties. */ - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = std::string(""), - const std::string *defValue = NULL) = 0; + void setProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = std::string("")) { + writeProperty(property, value, comment); + } + void setProperty(const std::string &property, + const char *value) { + setProperty(property, InitStateString(value, true)); + } + void setProperty(const std::string &property, + char *value) { + setProperty(property, InitStateString(value, true)); + } /** * Sets a boolean property, using "true/false". */ + void setProperty(const std::string &property, const InitState &value) { + setProperty(property, + InitStateString(value ? "true" : "false", + value.wasSet())); + } void setProperty(const std::string &property, bool value) { - setProperty(property, value ? "true" : "false"); + setProperty(property, InitState(value, true)); } /** @@ -99,22 +116,35 @@ class ConfigNode { * using stream formatting. */ template void setProperty(const std::string &property, - const T &value) { + const InitState &value) { std::stringstream strval; - strval << value; - setProperty(property, strval.str()); + strval << value.get(); + setProperty(property, + InitStateString(strval.str(), + value.wasSet())); + } + template void setProperty(const std::string &property, + const T &value) { + setProperty(property, + InitState(value, true)); } bool getProperty(const std::string &property, std::string &value) const { - value = readProperty(property); - return !value.empty(); + InitStateString str = readProperty(property); + if (str.wasSet()) { + value = str; + return true; + } else { + return false; + } } bool getProperty(const std::string &property, bool &value) const { - std::string str = readProperty(property); - if (str.empty()) { + InitStateString str = readProperty(property); + if (!str.wasSet() || + str.empty()) { return false; } @@ -144,8 +174,9 @@ class ConfigNode { template bool getProperty(const std::string &property, T &value) const { - std::string str = readProperty(property); - if (str.empty()) { + InitStateString str = readProperty(property); + if (!str.wasSet() || + str.empty()) { return false; } else { std::stringstream strval(str); @@ -158,6 +189,16 @@ class ConfigNode { typedef ConfigProps PropsType; /** + * Actual implementation of setProperty(). Uses different + * different name, to avoid shadowing the setProperty() + * variations in derived classes. + */ + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = std::string("")) = 0; + + + /** * Extract all list of all currently defined properties * and their values. Does not include values which were * initialized with their defaults, if the implementation diff --git a/src/syncevo/DBusTraits.h b/src/syncevo/DBusTraits.h index ee2de4f..14f2927 100644 --- a/src/syncevo/DBusTraits.h +++ b/src/syncevo/DBusTraits.h @@ -41,6 +41,34 @@ namespace GDBusCXX { dbus_enum_traits {}; + /** for InitState or InitStateClass: like a pair of two values, but with different storage class on the host */ + template struct dbus_init_state_traits : + public dbus_traits< std::pair > + { + typedef dbus_traits< std::pair > base_traits; + typedef I host_type; + typedef const I &arg_type; + + static void get(connection_type *conn, + message_type *msg, + reader_type &reader, host_type &value) + { + typename base_traits::host_type tmp; + base_traits::get(conn, msg, reader, tmp); + value = host_type(tmp.first, tmp.second); + } + + static void append(builder_type &builder, arg_type value) + { + base_traits::append(builder, typename base_traits::host_type(value.get(), value.wasSet())); + } + }; + + template struct dbus_traits< SyncEvo::InitStateClass > : + public dbus_init_state_traits< SyncEvo::InitStateClass > {}; + template struct dbus_traits< SyncEvo::InitState > : + public dbus_init_state_traits< SyncEvo::InitState > {}; + /** * Actual content is a std::map, so serialization can be done using that. * We only have to ensure that instances and parameters use FullProps. @@ -62,7 +90,7 @@ namespace GDBusCXX { typedef const SyncEvo::SourceProps &arg_type; }; template <> struct dbus_traits : - public dbus_traits < std::map > > + public dbus_traits < std::map > > { typedef SyncEvo::ConfigProps host_type; typedef const SyncEvo::ConfigProps &arg_type; diff --git a/src/syncevo/DevNullConfigNode.h b/src/syncevo/DevNullConfigNode.h index 77e14e3..c21ce69 100644 --- a/src/syncevo/DevNullConfigNode.h +++ b/src/syncevo/DevNullConfigNode.h @@ -36,11 +36,10 @@ class DevNullConfigNode : public ConfigNode { virtual string getName() const { return m_name; } virtual void flush() {} - virtual string readProperty(const string &property) const { return ""; } - virtual void setProperty(const string &property, - const string &value, - const string &comment = string(""), - const string *defValue = NULL) + virtual InitStateString readProperty(const string &property) const { return ""; } + virtual void writeProperty(const string &property, + const InitStateString &value, + const string &comment = string("")) { SE_THROW(m_name + ": virtual read-only configuration node, cannot write property " + property + " = " + value); diff --git a/src/syncevo/FileConfigNode.cpp b/src/syncevo/FileConfigNode.cpp deleted file mode 100644 index 2ff7cee..0000000 --- a/src/syncevo/FileConfigNode.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright (C) 2008-2009 Patrick Ohly - * 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 -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -SE_BEGIN_CXX - -FileBaseConfigNode::FileBaseConfigNode(const string &path, const string &fileName, bool readonly) : - m_path(path), - m_fileName(fileName), - m_modified(false), - m_readonly(readonly), - m_exists(false) -{ -} - -void FileBaseConfigNode::flush() -{ - if (!m_modified) { - return; - } - - if (m_readonly) { - throw std::runtime_error(m_path + "/" + m_fileName + ": internal error: flushing read-only file config node not allowed"); - } - - mkdir_p(m_path); - - string filename = m_path + "/" + m_fileName; - string tmpFilename = m_path + "/.#" + m_fileName; - - FILE *file = fopen(tmpFilename.c_str(), "w"); - if (file) { - toFile(file); - fflush(file); - bool failed = ferror(file); - if (fclose(file)) { - failed = true; - } - if (failed || - rename(tmpFilename.c_str(), filename.c_str())) { - SyncContext::throwError(tmpFilename, errno); - } - } else { - SyncContext::throwError(tmpFilename, errno); - } - - m_modified = false; - m_exists = true; -} - -FileConfigNode::FileConfigNode(const string &path, const string &fileName, bool readonly) : - FileBaseConfigNode(path,fileName,readonly) -{ - read(); -} - -void FileConfigNode::toFile(FILE* file) { - BOOST_FOREACH(const string &line, m_lines) { - fprintf(file, "%s\n", line.c_str()); - } -} - -void FileConfigNode::read() -{ - string filename = m_path + "/" + m_fileName; - - FILE *file = fopen(filename.c_str(), "r"); - char buffer[512]; - - m_lines.clear(); - if (file) { - /** add check to avoid errors when a line is larger than 512 bytes */ - string line; - while (fgets(buffer, sizeof(buffer), file)) { - char *eol = strchr(buffer, '\n'); - if (eol) { - *eol = 0; - line += buffer; - } else { - line += buffer; - continue; - } - m_lines.push_back(line); - line = ""; - } - m_exists = true; - fclose(file); - } - m_modified = false; -} - - -/** - * get property and value from line, if any present - */ -static bool getContent(const string &line, - string &property, - string &value, - bool &isComment, - bool fuzzyComments) -{ - size_t start = 0; - while (start < line.size() && - isspace(line[start])) { - start++; - } - - // empty line? - if (start == line.size()) { - return false; - } - - // Comment? Potentially keep reading, might be commented out assignment. - isComment = false; - if (line[start] == '#') { - if (!fuzzyComments) { - return false; - } - isComment = true; - } - - // recognize # = as commented out (= default) value - if (isComment) { - start++; - while (start < line.size() && - isspace(line[start])) { - start++; - } - } - - // extract property - size_t end = start; - while (end < line.size() && - !isspace(line[end])) { - end++; - } - property = line.substr(start, end - start); - - // skip assignment - start = end; - while (start < line.size() && - isspace(line[start])) { - start++; - } - if (start == line.size() || - line[start] != '=') { - // invalid syntax or we tried to read a comment as assignment - return false; - } - - // extract value - start++; - while (start < line.size() && - isspace(line[start])) { - start++; - } - - value = line.substr(start); - // remove trailing white space: usually it is - // added accidentally by users - size_t numspaces = 0; - while (numspaces < value.size() && - isspace(value[value.size() - 1 - numspaces])) { - numspaces++; - } - value.erase(value.size() - numspaces); - - // @TODO: strip quotation marks around value?! - - return true; -} - -/** - * check whether the line contains the property and if so, extract its value - */ -static bool getValue(const string &line, - const string &property, - string &value, - bool &isComment, - bool fuzzyComments) - -{ - string curProp; - return getContent(line, curProp, value, isComment, fuzzyComments) && - !strcasecmp(curProp.c_str(), property.c_str()); -} - -string FileConfigNode::readProperty(const string &property) const { - string value; - - BOOST_FOREACH(const string &line, m_lines) { - bool isComment; - - if (getValue(line, property, value, isComment, false)) { - return value; - } - } - return ""; -} - - - -void FileConfigNode::readProperties(ConfigProps &props) const { - map res; - string value, property; - - BOOST_FOREACH(const string &line, m_lines) { - bool isComment; - if (getContent(line, property, value, isComment, false)) { - // don't care about the result: only the first instance - // of the property counts, so it doesn't matter when - // inserting it again later fails - props.insert(pair(property, value)); - } - } -} - -void FileConfigNode::removeProperty(const string &property) -{ - string value; - - list::iterator it = m_lines.begin(); - while (it != m_lines.end()) { - const string &line = *it; - bool isComment; - if (getValue(line, property, value, isComment, false)) { - it = m_lines.erase(it); - m_modified = true; - } else { - it++; - } - } -} - -void FileConfigNode::setProperty(const string &property, - const string &newvalue, - const string &comment, - const string *defValue) { - string newstr; - string oldvalue; - bool isDefault = false; - - if (defValue && - *defValue == newvalue) { - newstr += "# "; - isDefault = true; - } - newstr += property + " = " + newvalue; - - BOOST_FOREACH(string &line, m_lines) { - bool isComment; - - if (getValue(line, property, oldvalue, isComment, true)) { - if (newvalue != oldvalue || - (isComment && !isDefault)) { - line = newstr; - m_modified = true; - } - return; - } - } - - // add each line of the comment as separate line in .ini file - if (comment.size()) { - list commentLines; - ConfigProperty::splitComment(comment, commentLines); - if (m_lines.size()) { - m_lines.push_back(""); - } - BOOST_FOREACH(const string &comment, commentLines) { - m_lines.push_back(string("# ") + comment); - } - } - - m_lines.push_back(newstr); - m_modified = true; -} - -void FileConfigNode::clear() -{ - m_lines.clear(); - m_modified = true; -} - -HashFileConfigNode::HashFileConfigNode(const string &path, const string &fileName, bool readonly) : - FileBaseConfigNode(path,fileName,readonly) -{ - read(); -} - -void HashFileConfigNode::read() -{ - string filename = m_path + "/" + m_fileName; - - FILE *file = fopen(filename.c_str(), "r"); - char buffer[512]; - - if (file) { - string line; - while (fgets(buffer, sizeof(buffer), file)) { - char *eol = strchr(buffer, '\n'); - if (eol) { - *eol = 0; - line += buffer; - }else{ - line += buffer; - continue; - } - string property, value; - bool isComment; - if (getContent(line, property, value, isComment, false)) { - m_props.insert(StringPair(property, value)); - } - line = ""; - } - m_exists = true; - fclose(file); - } - m_modified = false; -} - -void HashFileConfigNode::toFile(FILE* file) { - BOOST_FOREACH(const StringPair &prop, m_props) { - fprintf(file, "%s = %s\n", prop.first.c_str(),prop.second.c_str()); - } -} - -void HashFileConfigNode::readProperties(ConfigProps &props) const { - BOOST_FOREACH(const StringPair &prop, m_props) { - props.insert(prop); - } -} - -void HashFileConfigNode::writeProperties(const ConfigProps &props) { - if (!props.empty()) { - m_props.insert(props.begin(), props.end()); - m_modified = true; - } -} - - -string HashFileConfigNode::readProperty(const string &property) const { - std::map::const_iterator it = m_props.find(property); - if (it != m_props.end()) { - return it->second; - } else { - return ""; - } -} - -void HashFileConfigNode::removeProperty(const string &property){ - map::iterator it = m_props.find(property); - if(it != m_props.end()) { - m_props.erase(it); - m_modified = true; - } -} - -void HashFileConfigNode::clear() -{ - if (!m_props.empty()) { - m_props.clear(); - m_modified = true; - } -} - -void HashFileConfigNode::setProperty(const string &property, - const string &newvalue, - const string &comment, - const string *defValue) { - /** we don't support property comments here. Also, we ignore comment*/ - if (defValue && - *defValue == newvalue) { - removeProperty(property); - return; - } - map::iterator it = m_props.find(property); - if(it != m_props.end()) { - string oldvalue = it->second; - if(oldvalue != newvalue) { - m_props.erase(it); - m_props.insert(StringPair(property, newvalue)); - m_modified = true; - } - } else { - m_props.insert(StringPair(property, newvalue)); - m_modified = true; - } -} - - -SE_END_CXX diff --git a/src/syncevo/FileConfigNode.h b/src/syncevo/FileConfigNode.h deleted file mode 100644 index 672bded..0000000 --- a/src/syncevo/FileConfigNode.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2008-2009 Patrick Ohly - * - * 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 - */ - -#ifndef INCL_EVOLUTION_FILE_CONFIG_NODE -# define INCL_EVOLUTION_FILE_CONFIG_NODE - -#include - -#include -#include - -#include -SE_BEGIN_CXX - -/** - * A base class for file related config - */ -class FileBaseConfigNode: public ConfigNode { - protected: - std::string m_path; - std::string m_fileName; - bool m_modified; - const bool m_readonly; - bool m_exists; - - /** - * Open or create a new file. The file will be read (if it exists) - * but not create or written to unless flush() is called explicitly - * - * @param path node name, maps to directory - * @param fileName name of file inside that directory - * @param readonly do not create or write file, it must exist; - * flush() will throw an exception when changes would have to be written - */ - FileBaseConfigNode(const std::string &path, const std::string &fileName, bool readonly); - /** - * a virtual method to serial data structure to the file - * It is used by flush function to flush memory into disk file - */ - virtual void toFile(FILE* file) = 0; - public: - virtual void flush(); - virtual std::string getName() const { return m_path + "/" + m_fileName; } - virtual bool exists() const { return m_exists; } - virtual bool isReadOnly() const { return m_readonly; } -}; -/** - * This class started its life as the Posix implementation of the - * ManagementNode in the Funambol C++ client library. Nowadays it is - * part of the SyncEvoluition ConfigTree (see there for details). - * - * Each node is mapped to one file whose location is determined by - * the ConfigTree when the node gets created. Each node represents - * one .ini file with entries of the type - * \s*=\s*\s*\n - * - * Comments look like: - * \s*# - * - * @todo rewrite with standard C++ containers - */ -class FileConfigNode : public FileBaseConfigNode { - std::list m_lines; - - void read(); - - protected: - - virtual void toFile(FILE* file); - - public: - /** - * Open or create a new file. The file will be read (if it exists) - * but not create or written to unless flush() is called explicitly - * - * @param path node name, maps to directory - * @param fileName name of file inside that directory - * @param readonly do not create or write file, it must exist; - * flush() will throw an exception when changes would have to be written - */ - FileConfigNode(const std::string &path, const std::string &fileName, bool readonly); - - /* keep underlying methods visible; our own setProperty() would hide them */ - using ConfigNode::setProperty; - - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); - virtual void readProperties(ConfigProps &props) const; - virtual void removeProperty(const std::string &property); - virtual void clear(); -}; - -/** - * The main difference from FileConfigNode is to store pair of 'property-value' - * in a map to avoid O(n^2) string comparison - * Here comments for property default value are discarded. - */ -class HashFileConfigNode: public FileBaseConfigNode { - std::map m_props; - /** - * Map used to store pairs - */ - void read(); - - protected: - - virtual void toFile(FILE* file); - - public: - HashFileConfigNode(const std::string &path, const std::string &fileName, bool readonly); - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); - virtual void readProperties(ConfigProps &props) const; - virtual void writeProperties(const ConfigProps &props); - virtual void removeProperty(const std::string &property); - virtual void clear(); -}; - - -SE_END_CXX -#endif diff --git a/src/syncevo/FileConfigTree.cpp b/src/syncevo/FileConfigTree.cpp index 5c83cf6..fd46cba 100644 --- a/src/syncevo/FileConfigTree.cpp +++ b/src/syncevo/FileConfigTree.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -182,10 +182,10 @@ boost::shared_ptr FileConfigTree::open(const string &path, if (found != m_nodes.end()) { return found->second; } else if(type != other && type != server) { - boost::shared_ptr node(new FileConfigNode(fullpath, filename, m_readonly)); + boost::shared_ptr node(new IniFileConfigNode(fullpath, filename, m_readonly)); return m_nodes[fullname] = node; } else { - boost::shared_ptr node(new HashFileConfigNode(fullpath, filename, m_readonly)); + boost::shared_ptr node(new IniHashConfigNode(fullpath, filename, m_readonly)); return m_nodes[fullname] = node; } } diff --git a/src/syncevo/FilterConfigNode.cpp b/src/syncevo/FilterConfigNode.cpp index ee15f76..da17290 100644 --- a/src/syncevo/FilterConfigNode.cpp +++ b/src/syncevo/FilterConfigNode.cpp @@ -42,7 +42,7 @@ FilterConfigNode::FilterConfigNode(const boost::shared_ptr &no } void FilterConfigNode::addFilter(const string &property, - const string &value) + const InitStateString &value) { m_filter[property] = value; } @@ -52,7 +52,7 @@ void FilterConfigNode::setFilter(const ConfigFilter &filter) m_filter = filter; } -string FilterConfigNode::readProperty(const string &property) const +InitStateString FilterConfigNode::readProperty(const string &property) const { ConfigFilter::const_iterator it = m_filter.find(property); @@ -63,10 +63,9 @@ string FilterConfigNode::readProperty(const string &property) const } } -void FilterConfigNode::setProperty(const string &property, - const string &value, - const string &comment, - const string *defValue) +void FilterConfigNode::writeProperty(const string &property, + const InitStateString &value, + const string &comment) { ConfigFilter::iterator it = m_filter.find(property); @@ -77,7 +76,7 @@ void FilterConfigNode::setProperty(const string &property, if (it != m_filter.end()) { m_filter.erase(it); } - m_node->setProperty(property, value, comment, defValue); + m_node->writeProperty(property, value, comment); } void FilterConfigNode::readProperties(ConfigProps &props) const @@ -118,14 +117,4 @@ void FilterConfigNode::flush() m_node->flush(); } -FilterConfigNode::ConfigFilter::operator string () const { - vector res; - - BOOST_FOREACH(const StringPair &filter, *this) { - res.push_back(filter.first + " = " + filter.second); - } - sort(res.begin(), res.end()); - return boost::join(res, "\n"); -} - SE_END_CXX diff --git a/src/syncevo/FilterConfigNode.h b/src/syncevo/FilterConfigNode.h index 9f65ef1..3cbaff8 100644 --- a/src/syncevo/FilterConfigNode.h +++ b/src/syncevo/FilterConfigNode.h @@ -59,7 +59,7 @@ class FilterConfigNode : public ConfigNode { /** add another entry to the list of filter properties */ virtual void addFilter(const std::string &property, - const std::string &value); + const InitStateString &value); /** replace current filter list with new one */ virtual void setFilter(const ConfigFilter &filter); @@ -67,11 +67,10 @@ class FilterConfigNode : public ConfigNode { /* ConfigNode API */ virtual void flush(); - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); + virtual InitStateString readProperty(const std::string &property) const; + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = ""); virtual void readProperties(ConfigProps &props) const; virtual void removeProperty(const std::string &property); virtual bool exists() const { return m_readOnlyNode->exists(); } diff --git a/src/syncevo/IniConfigNode.cpp b/src/syncevo/IniConfigNode.cpp index 68aee5a..46d5c88 100644 --- a/src/syncevo/IniConfigNode.cpp +++ b/src/syncevo/IniConfigNode.cpp @@ -177,17 +177,18 @@ static bool getValue(const string &line, !strcasecmp(curProp.c_str(), property.c_str()); } -string IniFileConfigNode::readProperty(const string &property) const { +InitStateString IniFileConfigNode::readProperty(const string &property) const +{ string value; BOOST_FOREACH(const string &line, m_lines) { bool isComment; if (getValue(line, property, value, isComment, false)) { - return value; + return InitStateString(value, true); } } - return ""; + return InitStateString(); } void IniFileConfigNode::readProperties(ConfigProps &props) const { @@ -200,7 +201,7 @@ void IniFileConfigNode::readProperties(ConfigProps &props) const { // don't care about the result: only the first instance // of the property counts, so it doesn't matter when // inserting it again later fails - props.insert(pair(property, value)); + props.insert(ConfigProps::value_type(property, InitStateString(value, true))); } } } @@ -222,16 +223,14 @@ void IniFileConfigNode::removeProperty(const string &property) } } -void IniFileConfigNode::setProperty(const string &property, - const string &newvalue, - const string &comment, - const string *defValue) { +void IniFileConfigNode::writeProperty(const string &property, + const InitStateString &newvalue, + const string &comment) { string newstr; string oldvalue; bool isDefault = false; - if (defValue && - *defValue == newvalue) { + if (!newvalue.wasSet()) { newstr += "# "; isDefault = true; } @@ -308,7 +307,7 @@ void IniHashConfigNode::toFile(std::ostream &file) void IniHashConfigNode::readProperties(ConfigProps &props) const { BOOST_FOREACH(const StringPair &prop, m_props) { - props.insert(prop); + props.insert(ConfigProps::value_type(prop.first, InitStateString(prop.second, true))); } } @@ -321,13 +320,13 @@ void IniHashConfigNode::writeProperties(const ConfigProps &props) } -string IniHashConfigNode::readProperty(const string &property) const +InitStateString IniHashConfigNode::readProperty(const string &property) const { std::map::const_iterator it = m_props.find(property); if (it != m_props.end()) { - return it->second; + return InitStateString(it->second, true); } else { - return ""; + return InitStateString(); } } @@ -347,23 +346,19 @@ void IniHashConfigNode::clear() } } -void IniHashConfigNode::setProperty(const string &property, - const string &newvalue, - const string &comment, - const string *defValue) +void IniHashConfigNode::writeProperty(const string &property, + const InitStateString &newvalue, + const string &comment) { - /** we don't support property comments here. Also, we ignore comment*/ - if (defValue && - *defValue == newvalue) { + // we only store explicitly set properties + if (!newvalue.wasSet()) { removeProperty(property); return; } map::iterator it = m_props.find(property); if(it != m_props.end()) { - string oldvalue = it->second; - if(oldvalue != newvalue) { - m_props.erase(it); - m_props.insert(StringPair(property, newvalue)); + if (it->second != newvalue) { + it->second = newvalue; m_modified = true; } } else { diff --git a/src/syncevo/IniConfigNode.h b/src/syncevo/IniConfigNode.h index e918f85..1c935d9 100644 --- a/src/syncevo/IniConfigNode.h +++ b/src/syncevo/IniConfigNode.h @@ -86,11 +86,10 @@ class IniFileConfigNode : public IniBaseConfigNode { /* keep underlying methods visible; our own setProperty() would hide them */ using ConfigNode::setProperty; - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); + virtual InitStateString readProperty(const std::string &property) const; + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = ""); virtual void readProperties(ConfigProps &props) const; virtual void removeProperty(const std::string &property); virtual void clear(); @@ -100,7 +99,8 @@ class IniFileConfigNode : public IniBaseConfigNode { /** * The main difference from FileConfigNode is to store pair of 'property-value' * in a map to avoid O(n^2) string comparison - * Here comments for property default value are discarded. + * Here comments for property default value are discarded and unset + * properties are not stored. */ class IniHashConfigNode: public IniBaseConfigNode { std::map m_props; @@ -116,11 +116,10 @@ class IniHashConfigNode: public IniBaseConfigNode { public: IniHashConfigNode(const boost::shared_ptr &data); IniHashConfigNode(const std::string &path, const std::string &fileName, bool readonly); - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); + virtual InitStateString readProperty(const std::string &property) const; + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = ""); virtual void readProperties(ConfigProps &props) const; virtual void writeProperties(const ConfigProps &props); virtual void removeProperty(const std::string &property); diff --git a/src/syncevo/MultiplexConfigNode.cpp b/src/syncevo/MultiplexConfigNode.cpp index b331fa0..babdbcd 100644 --- a/src/syncevo/MultiplexConfigNode.cpp +++ b/src/syncevo/MultiplexConfigNode.cpp @@ -50,7 +50,7 @@ MultiplexConfigNode::getNode(const std::string &property, } void MultiplexConfigNode::addFilter(const std::string &property, - const std::string &value) + const InitStateString &value) { FilterConfigNode::addFilter(property, value); for (int i = 0; i < 2; i++) { @@ -85,25 +85,24 @@ void MultiplexConfigNode::flush() } } -std::string MultiplexConfigNode::readProperty(const std::string &property) const +InitStateString MultiplexConfigNode::readProperty(const std::string &property) const { FilterConfigNode *node = getNode(property); if (node) { return node->readProperty(property); } else { - return ""; + return InitStateString(); } } -void MultiplexConfigNode::setProperty(const std::string &property, - const std::string &value, - const std::string &comment, - const std::string *defValue) +void MultiplexConfigNode::writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment) { const ConfigProperty *prop; FilterConfigNode *node = getNode(property, &prop); if (node) { - node->setProperty(property, value, comment, defValue); + node->writeProperty(property, value, comment); } else { SE_THROW(property + ": not supported by configuration multiplexer"); } diff --git a/src/syncevo/MultiplexConfigNode.h b/src/syncevo/MultiplexConfigNode.h index 16ba77f..5e4d080 100644 --- a/src/syncevo/MultiplexConfigNode.h +++ b/src/syncevo/MultiplexConfigNode.h @@ -77,16 +77,15 @@ class MultiplexConfigNode : public FilterConfigNode } virtual void addFilter(const std::string &property, - const std::string &value); + const InitStateString &value); virtual void setFilter(const ConfigFilter &filter); virtual std::string getName() const { return m_name; } virtual void flush(); - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = std::string(""), - const std::string *defValue = NULL); + virtual InitStateString readProperty(const std::string &property) const; + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = std::string("")); virtual void readProperties(PropsType &props) const; /* diff --git a/src/syncevo/PrefixConfigNode.cpp b/src/syncevo/PrefixConfigNode.cpp index 85b1620..08d6828 100644 --- a/src/syncevo/PrefixConfigNode.cpp +++ b/src/syncevo/PrefixConfigNode.cpp @@ -41,20 +41,18 @@ PrefixConfigNode::PrefixConfigNode(const string prefix, { } -string PrefixConfigNode::readProperty(const string &property) const +InitStateString PrefixConfigNode::readProperty(const string &property) const { return m_readOnlyNode->readProperty(m_prefix + property); } -void PrefixConfigNode::setProperty(const string &property, - const string &value, - const string &comment, - const string *defValue) +void PrefixConfigNode::writeProperty(const string &property, + const InitStateString &value, + const string &comment) { - m_node->setProperty(m_prefix + property, - value, - comment, - defValue); + m_node->writeProperty(m_prefix + property, + value, + comment); } void PrefixConfigNode::readProperties(ConfigProps &props) const diff --git a/src/syncevo/PrefixConfigNode.h b/src/syncevo/PrefixConfigNode.h index 049759d..c235822 100644 --- a/src/syncevo/PrefixConfigNode.h +++ b/src/syncevo/PrefixConfigNode.h @@ -54,11 +54,10 @@ class PrefixConfigNode : public ConfigNode { /* ConfigNode API */ virtual void flush(); - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); + virtual InitStateString readProperty(const std::string &property) const; + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = ""); virtual void readProperties(ConfigProps &props) const; virtual void removeProperty(const std::string &property); virtual bool exists() const { return m_readOnlyNode->exists(); } diff --git a/src/syncevo/SafeConfigNode.cpp b/src/syncevo/SafeConfigNode.cpp index 7f56d5c..2ea8ec0 100644 --- a/src/syncevo/SafeConfigNode.cpp +++ b/src/syncevo/SafeConfigNode.cpp @@ -38,20 +38,19 @@ SafeConfigNode::SafeConfigNode(const boost::shared_ptr &node) { } -string SafeConfigNode::readProperty(const string &property) const +InitStateString SafeConfigNode::readProperty(const string &property) const { - return unescape(m_readOnlyNode->readProperty(escape(property))); + InitStateString res = m_readOnlyNode->readProperty(escape(property)); + return InitStateString(unescape(res.get()), res.wasSet()); } -void SafeConfigNode::setProperty(const string &property, - const string &value, - const string &comment, - const string *defValue) +void SafeConfigNode::writeProperty(const string &property, + const InitStateString &value, + const string &comment) { - m_node->setProperty(escape(property), - escape(value), - comment, - defValue); + m_node->writeProperty(escape(property), + InitStateString(escape(value.get()), value.wasSet()), + comment); } void SafeConfigNode::readProperties(ConfigProps &props) const diff --git a/src/syncevo/SafeConfigNode.h b/src/syncevo/SafeConfigNode.h index 1297ff8..818f504 100644 --- a/src/syncevo/SafeConfigNode.h +++ b/src/syncevo/SafeConfigNode.h @@ -63,11 +63,10 @@ class SafeConfigNode : public ConfigNode { /* ConfigNode API */ virtual void flush(); - virtual std::string readProperty(const std::string &property) const; - virtual void setProperty(const std::string &property, - const std::string &value, - const std::string &comment = "", - const std::string *defValue = NULL); + virtual InitStateString readProperty(const std::string &property) const; + virtual void writeProperty(const std::string &property, + const InitStateString &value, + const std::string &comment = ""); virtual void readProperties(ConfigProps &props) const; virtual void removeProperty(const std::string &property); virtual bool exists() const { return m_readOnlyNode->exists(); } diff --git a/src/syncevo/SingleFileConfigTree.cpp b/src/syncevo/SingleFileConfigTree.cpp index aa546f3..4cc4232 100644 --- a/src/syncevo/SingleFileConfigTree.cpp +++ b/src/syncevo/SingleFileConfigTree.cpp @@ -213,27 +213,31 @@ class SingleIniTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(node); CPPUNIT_ASSERT(node->exists()); CPPUNIT_ASSERT_EQUAL(string("test - /foo/config.ini"), node->getName()); - CPPUNIT_ASSERT_EQUAL(string("bar"), node->readProperty("foo")); - CPPUNIT_ASSERT_EQUAL(string("bar2"), node->readProperty("foo2")); + CPPUNIT_ASSERT(node->readProperty("foo").wasSet()); + CPPUNIT_ASSERT_EQUAL(string("bar"), node->readProperty("foo").get()); + CPPUNIT_ASSERT_EQUAL(string("bar2"), node->readProperty("foo2").get()); + CPPUNIT_ASSERT(node->readProperty("foo2").wasSet()); + CPPUNIT_ASSERT_EQUAL(string(""), node->readProperty("no_such_bar").get()); + CPPUNIT_ASSERT(!node->readProperty("no_such_bar").wasSet()); node = tree.open("/foo/config.ini"); CPPUNIT_ASSERT(node); CPPUNIT_ASSERT(node->exists()); node = tree.open("foo//.config.ini"); CPPUNIT_ASSERT(node); CPPUNIT_ASSERT(node->exists()); - CPPUNIT_ASSERT_EQUAL(string("bar_internal"), node->readProperty("foo_internal")); - CPPUNIT_ASSERT_EQUAL(string("bar2_internal"), node->readProperty("foo2_internal")); + CPPUNIT_ASSERT_EQUAL(string("bar_internal"), node->readProperty("foo_internal").get()); + CPPUNIT_ASSERT_EQUAL(string("bar2_internal"), node->readProperty("foo2_internal").get()); node = tree.open("bar///./.internal.ini"); CPPUNIT_ASSERT(node); CPPUNIT_ASSERT(node->exists()); - CPPUNIT_ASSERT_EQUAL(string("foo"), node->readProperty("bar")); + CPPUNIT_ASSERT_EQUAL(string("foo"), node->readProperty("bar").get()); node = tree.open("sources/addressbook/config.ini"); CPPUNIT_ASSERT(node); CPPUNIT_ASSERT(node->exists()); node = tree.open("sources/calendar/config.ini"); CPPUNIT_ASSERT(node); CPPUNIT_ASSERT(node->exists()); - CPPUNIT_ASSERT_EQUAL(string("Personal"), node->readProperty("evolutionsource")); + CPPUNIT_ASSERT_EQUAL(string("Personal"), node->readProperty("evolutionsource").get()); node = tree.open("no-such-source/config.ini"); CPPUNIT_ASSERT(node); diff --git a/src/syncevo/SyncConfig.cpp b/src/syncevo/SyncConfig.cpp index 64ddbe1..0f64264 100644 --- a/src/syncevo/SyncConfig.cpp +++ b/src/syncevo/SyncConfig.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -428,9 +429,9 @@ SyncConfig::SyncConfig(const string &peer, path = m_peerPath; if (path.empty()) { if (!m_redirectPeerRootPath.empty()) { - node.reset(new FileConfigNode(m_redirectPeerRootPath, - ".internal.ini", - false)); + node.reset(new IniFileConfigNode(m_redirectPeerRootPath, + ".internal.ini", + false)); node = m_tree->add(m_redirectPeerRootPath + "/.internal.ini", node); } else { @@ -837,7 +838,7 @@ boost::shared_ptr SyncConfig::createPeerTemplate(const string &serve // up in the UI. if (server == "default") { config->setConsumerReady(true); - config->setUserPeerName(""); + config->setUserPeerName(InitStateString()); } return config; @@ -1059,11 +1060,17 @@ SyncSourceNodes SyncConfig::getSyncSourceNodes(const string &name, node = m_tree->open(peerPath, ConfigTree::visible); if (compatMode) { boost::shared_ptr compat(new FilterConfigNode(node)); - compat->addFilter("syncFormat", sourceType.m_format); - compat->addFilter("forceSyncFormat", sourceType.m_forceFormat ? "1" : "0"); + compat->addFilter("syncFormat", + InitStateString(sourceType.m_format, !sourceType.m_format.empty())); + compat->addFilter("forceSyncFormat", + sourceType.m_forceFormat ? + InitStateString("1", true) : + InitStateString("0", false)); if (sharedPath.empty()) { - compat->addFilter("databaseFormat", sourceType.m_localFormat); - compat->addFilter("backend", sourceType.m_backend); + compat->addFilter("databaseFormat", + InitStateString(sourceType.m_localFormat, !sourceType.m_localFormat.empty())); + compat->addFilter("backend", + InitStateString(sourceType.m_backend, !sourceType.m_backend.empty())); } node = compat; } @@ -1079,13 +1086,13 @@ SyncSourceNodes SyncConfig::getSyncSourceNodes(const string &name, // against the same context end up sharing .internal.ini and // .other.ini files inside that context. string path = m_redirectPeerRootPath + "/sources/" + lower; - trackingNode.reset(new HashFileConfigNode(path, - ".other.ini", - false)); + trackingNode.reset(new IniHashConfigNode(path, + ".other.ini", + false)); trackingNode = m_tree->add(path + "/.other.ini", trackingNode); - boost::shared_ptr node(new HashFileConfigNode(path, - ".internal.ini", - false)); + boost::shared_ptr node(new IniHashConfigNode(path, + ".internal.ini", + false)); hiddenPeerNode.reset(new FilterConfigNode(node)); hiddenPeerNode = boost::static_pointer_cast(m_tree->add(path + "/.internal.ini", peerNode)); if (peerPath.empty()) { @@ -1099,8 +1106,10 @@ SyncSourceNodes SyncConfig::getSyncSourceNodes(const string &name, node = m_tree->open(sharedPath, ConfigTree::visible); if (compatMode) { boost::shared_ptr compat(new FilterConfigNode(node)); - compat->addFilter("databaseFormat", sourceType.m_localFormat); - compat->addFilter("backend", sourceType.m_backend); + compat->addFilter("databaseFormat", + InitStateString(sourceType.m_localFormat, !sourceType.m_localFormat.empty())); + compat->addFilter("backend", + InitStateString(sourceType.m_backend, !sourceType.m_backend.empty())); node = compat; } sharedNode.reset(new FilterConfigNode(node, m_sourceFilters.createSourceFilter(name))); @@ -1712,9 +1721,9 @@ void PasswordConfigProperty::checkPassword(UserInterface &ui, * Previous impl use temp string to store them, this is not good for expansion in the backend */ if(!passwordSave.empty()) { if(sourceConfigNode.get() == NULL) { - globalConfigNode.addFilter(getMainName(), passwordSave); + globalConfigNode.addFilter(getMainName(), InitStateString(passwordSave, true)); } else { - sourceConfigNode->addFilter(getMainName(), passwordSave); + sourceConfigNode->addFilter(getMainName(), InitStateString(passwordSave, true)); } } } @@ -1914,7 +1923,7 @@ InitStateString SyncConfig::getSyncMLVersion() const { return syncPropSyncMLVers void SyncConfig::setSyncMLVersion(const string &value, bool temporarily) { syncPropSyncMLVersion.setProperty(*getNode(syncPropSyncMLVersion), value, temporarily); } InitStateString SyncConfig::getUserPeerName() const { return syncPropPeerName.getProperty(*getNode(syncPropPeerName)); } -void SyncConfig::setUserPeerName(const string &name) { syncPropPeerName.setProperty(*getNode(syncPropPeerName), name); } +void SyncConfig::setUserPeerName(const InitStateString &name) { syncPropPeerName.setProperty(*getNode(syncPropPeerName), name); } InitState SyncConfig::getPrintChanges() const { return syncPropPrintChanges.getPropertyValue(*getNode(syncPropPrintChanges)); } void SyncConfig::setPrintChanges(bool value, bool temporarily) { syncPropPrintChanges.setProperty(*getNode(syncPropPrintChanges), value, temporarily); } @@ -2131,8 +2140,9 @@ static void copyProperties(const ConfigNode &fromProps, prop->getSharing() != ConfigProperty::NO_SHARING)) { InitStateString value = prop->getProperty(fromProps); string name = prop->getName(toProps); - toProps.setProperty(name, value, prop->getComment(), - !value.wasSet() ? &value : NULL); + toProps.setProperty(name, + value, + prop->getComment()); } } } @@ -2608,7 +2618,7 @@ void SyncSourceConfig::setSourceType(const SourceType &type, bool temporarily) // been converted to the new format before writing is allowed setBackend(type.m_backend, temporarily); setDatabaseFormat(type.m_localFormat, temporarily); - setSyncFormat(type.m_format, temporarily); + setSyncFormat(InitStateString(type.m_format, !type.m_format.empty()), temporarily); setForceSyncFormat(type.m_forceFormat, temporarily); } @@ -2634,7 +2644,7 @@ InitStateString SyncSourceConfig::getDatabaseFormat() const return sourcePropDatabaseFormat.getProperty(*getNode(sourcePropDatabaseFormat)); } -void SyncSourceConfig::setSyncFormat(const std::string &value, bool temporarily) +void SyncSourceConfig::setSyncFormat(const InitStateString &value, bool temporarily) { sourcePropSyncFormat.setProperty(*getNode(sourcePropSyncFormat), value, diff --git a/src/syncevo/SyncConfig.h b/src/syncevo/SyncConfig.h index 85ccaab..e2f80c2 100644 --- a/src/syncevo/SyncConfig.h +++ b/src/syncevo/SyncConfig.h @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -347,8 +346,15 @@ class ConfigProperty { void setSharing(Sharing sharing) { m_sharing = sharing; } /** set value unconditionally, even if it is not valid */ - void setProperty(ConfigNode &node, const std::string &value) const { node.setProperty(getName(node), value, getComment()); } - void setProperty(FilterConfigNode &node, const std::string &value, bool temporarily = false) const { + void setProperty(ConfigNode &node, const InitStateString &value) const { + node.setProperty(getName(node), + value, + getComment()); + } + void setProperty(ConfigNode &node, const std::string &value) const { + setProperty(node, InitStateString(value, true)); + } + void setProperty(FilterConfigNode &node, const InitStateString &value, bool temporarily = false) const { std::string name = getName(node); if (temporarily) { node.addFilter(name, value); @@ -356,12 +362,13 @@ class ConfigProperty { node.setProperty(name, value, getComment()); } } + void setProperty(FilterConfigNode &node, const std::string &value, bool temporarily = false) const { + setProperty(node, InitStateString(value, true), temporarily); + } - /** set default value of a property, marked as default unless forced setting */ + /** set default value of a property, marked as unset unless "force" is true */ void setDefaultProperty(ConfigNode &node, bool force) const { - std::string name = getName(node); - std::string defValue = getDefValue(); - node.setProperty(name, defValue, getComment(), force ? NULL : &defValue); + setProperty(node, InitStateString(m_defValue, force)); } /** @@ -371,27 +378,19 @@ class ConfigProperty { */ virtual InitStateString getProperty(const ConfigNode &node) const { std::string name = getName(node); - std::string value = node.readProperty(name); - if (!value.empty()) { - // value was set + InitStateString value = node.readProperty(name); + if (value.wasSet()) { std::string error; if (!checkValue(value, error)) { throwValueError(node, name, value, error); } - return InitStateString(value, true); + return value; } else { // default return InitStateString(getDefValue(), false); } } - // true if property is set to non-empty value - bool isSet(const ConfigNode &node) const { - std::string name = getName(node); - std::string value = node.readProperty(name); - return !value.empty(); - } - protected: void throwValueError(const ConfigNode &node, const std::string &name, const std::string &value, const std::string &error) const; @@ -531,10 +530,11 @@ template class TypedConfigProperty : public ConfigProperty { std::string name = getName(node); out << value; + InitStateString res(out.str(), true); if (temporarily) { - node.addFilter(name, out.str()); + node.addFilter(name, res); } else { - node.setProperty(name, out.str(), getComment()); + node.setProperty(name, res, getComment()); } } @@ -785,10 +785,10 @@ class BoolConfigProperty : public StringConfigProperty { {} void setProperty(ConfigNode &node, bool value) { - StringConfigProperty::setProperty(node, value ? "1" : "0"); + StringConfigProperty::setProperty(node, InitStateString(value ? "1" : "0", true)); } void setProperty(FilterConfigNode &node, bool value, bool temporarily = false) { - StringConfigProperty::setProperty(node, value ? "1" : "0", temporarily); + StringConfigProperty::setProperty(node, InitStateString(value ? "1" : "0", true), temporarily); } InitState getPropertyValue(const ConfigNode &node) const { InitStateString res = ConfigProperty::getProperty(node); @@ -809,8 +809,15 @@ class SafeConfigProperty : public ConfigProperty { ConfigProperty(name, comment) {} + void setProperty(ConfigNode &node, const InitStateString &value) { + ConfigProperty::setProperty(node, + InitStateString(StringEscape::escape(value, '!', StringEscape::INI_WORD), + value.wasSet())); + } void setProperty(ConfigNode &node, const std::string &value) { - ConfigProperty::setProperty(node, StringEscape::escape(value, '!', StringEscape::INI_WORD)); + ConfigProperty::setProperty(node, + InitStateString(StringEscape::escape(value, '!', StringEscape::INI_WORD), + true)); } virtual InitStateString getProperty(const ConfigNode &node) const { InitStateString res = ConfigProperty::getProperty(node); @@ -1491,10 +1498,10 @@ class SyncConfig { /** * An arbitrary name assigned to the peer configuration, * not necessarily unique. Can be used by a GUI instead - * of the config name. + * of the config name. Unsetting it is supported. */ virtual InitStateString getUserPeerName() const; - virtual void setUserPeerName(const std::string &name); + virtual void setUserPeerName(const InitStateString &name); /** * The Device ID of our peer. Typically only relevant when the @@ -1839,11 +1846,6 @@ class SyncSourceConfig { /** true if the source config exists with view-specific properties (not just default or shared ones) */ bool exists() const { return m_nodes.exists(); } - /** checks if a certain property is set to a non-empty value */ - bool isSet(ConfigProperty &prop) { - return prop.isSet(*getProperties(prop.isHidden())); - } - virtual InitStateString getUser() const; virtual void setUser(const std::string &value, bool temporarily = false); @@ -1885,7 +1887,7 @@ class SyncSourceConfig { virtual InitStateString getBackend() const; virtual void setDatabaseFormat(const std::string &value, bool temporarily = false); virtual InitStateString getDatabaseFormat() const; - virtual void setSyncFormat(const std::string &value, bool temporarily = false); + virtual void setSyncFormat(const InitStateString &value, bool temporarily = false); virtual InitStateString getSyncFormat() const; virtual void setForceSyncFormat(bool value, bool temporarily = false); virtual InitState getForceSyncFormat() const; diff --git a/src/syncevo/SyncContext.cpp b/src/syncevo/SyncContext.cpp index ae5ad9b..42df0c6 100644 --- a/src/syncevo/SyncContext.cpp +++ b/src/syncevo/SyncContext.cpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -376,7 +376,7 @@ public: * access existing log directory to extract status information */ void openLogdir(const string &dir) { - boost::shared_ptr filenode(new FileConfigNode(dir, "status.ini", true)); + boost::shared_ptr filenode(new IniFileConfigNode(dir, "status.ini", true)); m_info.reset(new SafeConfigNode(filenode)); m_info->setMode(false); m_readonly = true; @@ -544,14 +544,14 @@ public: } m_readonly = mode == SESSION_READ_ONLY; if (!m_path.empty()) { - boost::shared_ptr filenode(new FileConfigNode(m_path, "status.ini", m_readonly)); + boost::shared_ptr filenode(new IniFileConfigNode(m_path, "status.ini", m_readonly)); m_info.reset(new SafeConfigNode(filenode)); m_info->setMode(false); if (mode != SESSION_READ_ONLY) { // Create a status.ini which contains an error. // Will be overwritten later on, unless we crash. m_info->setProperty("status", STATUS_DIED_PREMATURELY); - m_info->setProperty("error", "synchronization process died prematurely"); + m_info->setProperty("error", InitStateString("synchronization process died prematurely", true)); writeTimestamp("start", start); } } @@ -2872,12 +2872,18 @@ void SyncContext::setStableRelease(bool isStableRelease) IsStableRelease = isStableRelease; } -void SyncContext::checkConfig() const +void SyncContext::checkConfig(const std::string &operation) const { + std::string peer, context; + splitConfigString(m_server, peer, context); if (isConfigNeeded() && - !exists()) { - SE_LOG_ERROR(NULL, NULL, "No configuration for server \"%s\" found.", m_server.c_str()); - throwError("cannot proceed without configuration"); + (!exists() || peer.empty())) { + if (peer.empty()) { + SE_LOG_INFO(NULL, NULL, "Configuration \"%s\" does not refer to a sync peer.", m_server.c_str()); + } else { + SE_LOG_INFO(NULL, NULL, "Configuration \"%s\" does not exist.", m_server.c_str()); + } + throwError(StringPrintf("Cannot proceed with %s without a configuration.", operation.c_str())); } } @@ -2885,7 +2891,7 @@ SyncMLStatus SyncContext::sync(SyncReport *report) { SyncMLStatus status = STATUS_OK; - checkConfig(); + checkConfig("sync"); // redirect logging as soon as possible SourceList sourceList(*this, m_doLogging); @@ -3895,7 +3901,7 @@ SyncMLStatus SyncContext::handleException() void SyncContext::status() { - checkConfig(); + checkConfig("status check"); SourceList sourceList(*this, false); initSources(sourceList); @@ -3947,7 +3953,7 @@ void SyncContext::status() void SyncContext::checkStatus(SyncReport &report) { - checkConfig(); + checkConfig("status check"); SourceList sourceList(*this, false); initSources(sourceList); @@ -4037,7 +4043,7 @@ bool SyncContext::checkForScriptAbort(SharedSession session) void SyncContext::restore(const string &dirname, RestoreDatabase database) { - checkConfig(); + checkConfig("restore"); SourceList sourceList(*this, false); sourceList.accessSession(dirname.c_str()); @@ -4367,11 +4373,11 @@ private: Sessions_t sessions = listSessions(); CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size()); CPPUNIT_ASSERT_EQUAL(dir, sessions[0]); - FileConfigNode status(dir, "status.ini", true); + IniFileConfigNode status(dir, "status.ini", true); CPPUNIT_ASSERT(status.exists()); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-before")); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-after")); - CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status")); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-before").get()); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-after").get()); + CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status").get()); CPPUNIT_ASSERT(!LogDir::haveDifferentContent("file_event", dir, "before", dir, "after")); @@ -4386,11 +4392,11 @@ private: Sessions_t sessions = listSessions(); CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size()); CPPUNIT_ASSERT_EQUAL(dir, sessions[0]); - FileConfigNode status(dir, "status.ini", true); + IniFileConfigNode status(dir, "status.ini", true); CPPUNIT_ASSERT(status.exists()); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-before")); - CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__event-backup-after")); - CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status")); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-before").get()); + CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__event-backup-after").get()); + CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status").get()); CPPUNIT_ASSERT(LogDir::haveDifferentContent("file_event", dir, "before", dir, "after")); @@ -4410,13 +4416,13 @@ private: Sessions_t sessions = listSessions(); CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size()); CPPUNIT_ASSERT_EQUAL(dir, sessions[0]); - FileConfigNode status(dir, "status.ini", true); + IniFileConfigNode status(dir, "status.ini", true); CPPUNIT_ASSERT(status.exists()); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-before")); - CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__event-backup-after")); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__contact-backup-before")); - CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__contact-backup-after")); - CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status")); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-before").get()); + CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__event-backup-after").get()); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__contact-backup-before").get()); + CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__contact-backup-after").get()); + CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status").get()); CPPUNIT_ASSERT(LogDir::haveDifferentContent("file_event", dir, "before", dir, "after")); @@ -4434,13 +4440,13 @@ private: CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size()); CPPUNIT_ASSERT_EQUAL(dir, sessions[0]); CPPUNIT_ASSERT_EQUAL(seconddir, sessions[1]); - FileConfigNode status(seconddir, "status.ini", true); + IniFileConfigNode status(seconddir, "status.ini", true); CPPUNIT_ASSERT(status.exists()); - CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__event-backup-before")); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-after")); - CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__contact-backup-before")); - CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__contact-backup-after")); - CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status")); + CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__event-backup-before").get()); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__event-backup-after").get()); + CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-file__contact-backup-before").get()); + CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-file__contact-backup-after").get()); + CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status").get()); CPPUNIT_ASSERT(LogDir::haveDifferentContent("file_event", seconddir, "before", seconddir, "after")); diff --git a/src/syncevo/SyncContext.h b/src/syncevo/SyncContext.h index f410ebb..f5b3dac 100644 --- a/src/syncevo/SyncContext.h +++ b/src/syncevo/SyncContext.h @@ -237,8 +237,10 @@ class SyncContext : public SyncConfig { /** * throws error if config is needed and not available + * + * @param operation a noun describing what is to be done next ("proceed with %s", operation) */ - void checkConfig() const; + void checkConfig(const std::string &operation) const; /** * Sets configuration filters. Currently only used in local sync diff --git a/src/syncevo/SyncSource.cpp b/src/syncevo/SyncSource.cpp index b94aa9f..70d3e7b 100644 --- a/src/syncevo/SyncSource.cpp +++ b/src/syncevo/SyncSource.cpp @@ -1328,7 +1328,7 @@ sysync::TSyError SyncSourceAdmin::updateMapItem(sysync::cMapID mID) string key, value; mapid2entry(mID, key, value); - StringMap::iterator it = m_mapping.find(key); + ConfigProps::iterator it = m_mapping.find(key); if (it == m_mapping.end()) { // error, does not exist return sysync::DB_Forbidden; @@ -1346,7 +1346,7 @@ sysync::TSyError SyncSourceAdmin::deleteMapItem(sysync::cMapID mID) string key, value; mapid2entry(mID, key, value); - StringMap::iterator it = m_mapping.find(key); + ConfigProps::iterator it = m_mapping.find(key); if (it == m_mapping.end()) { // error, does not exist return sysync::DB_Forbidden; diff --git a/src/syncevo/VolatileConfigNode.h b/src/syncevo/VolatileConfigNode.h index 571c9b2..b874aad 100644 --- a/src/syncevo/VolatileConfigNode.h +++ b/src/syncevo/VolatileConfigNode.h @@ -21,20 +21,21 @@ # define INCL_EVOLUTION_VOLATILE_CONFIG_NODE #include -#include +#include #include SE_BEGIN_CXX /** * This class can store properties while in memory, but will never - * save them persistently. Implemented by instantiating a FileConfigNode + * save them persistently. Implemented by instantiating an IniHashConfigNode + * (because order of entries doesn't matter) * with invalid path and never calling its flush() method. */ class VolatileConfigNode : public FilterConfigNode { public: VolatileConfigNode() : - FilterConfigNode(boost::shared_ptr(new FileConfigNode("/dev/null", "dummy.ini", true))) + FilterConfigNode(boost::shared_ptr(new IniHashConfigNode("/dev/null", "dummy.ini", true))) {} virtual std::string getName() const { return "intermediate configuration"; } diff --git a/src/syncevo/syncevo.am b/src/syncevo/syncevo.am index 790a5cb..2ecce45 100644 --- a/src/syncevo/syncevo.am +++ b/src/syncevo/syncevo.am @@ -104,9 +104,6 @@ src_syncevo_sources = \ src/syncevo/PrefixConfigNode.h \ src/syncevo/PrefixConfigNode.cpp \ \ - src/syncevo/FileConfigNode.h \ - src/syncevo/FileConfigNode.cpp \ - \ src/syncevo/IniConfigNode.h \ src/syncevo/IniConfigNode.cpp \ src/syncevo/SingleFileConfigTree.h \ @@ -148,7 +145,6 @@ src_syncevo_libsyncevolution_include_HEADERS = \ src/syncevo/LogRedirect.h \ src/syncevo/LogStdout.h \ src/syncevo/LogSyslog.h \ - src/syncevo/FileConfigNode.h \ \ src/syncevo/FilterConfigNode.h \ src/syncevo/PrefixConfigNode.h \ diff --git a/src/syncevo/util.h b/src/syncevo/util.h index 674c1a7..5478ec3 100644 --- a/src/syncevo/util.h +++ b/src/syncevo/util.h @@ -363,6 +363,8 @@ template class Init { */ template class InitState { public: + typedef T value_type; + InitState(const T &val, bool wasSet) : m_value(val), m_wasSet(wasSet) {} InitState() : m_value(boost::value_initialized()), m_wasSet(false) {} InitState(const InitState &other) : m_value(other.m_value), m_wasSet(other.m_wasSet) {} @@ -380,6 +382,8 @@ template class InitState { /** version of InitState for classes */ template class InitStateClass : public T { public: + typedef T value_type; + InitStateClass(const T &val, bool wasSet) : T(val), m_wasSet(wasSet) {} InitStateClass() : m_wasSet(false) {} InitStateClass(const char *val) : T(val), m_wasSet(false) {} diff --git a/src/synthesis/ChangeLog b/src/synthesis/ChangeLog index a8d2812..331e228 100644 --- a/src/synthesis/ChangeLog +++ b/src/synthesis/ChangeLog @@ -1,6 +1,14 @@ # Generated by configure. Do not edit. -# git revision 2d7d1b25944d4d1ebd5ea2b04b106526d37ef1f9 -# git tag libsynthesis_3.4.0.16+syncevolution-1-2-2-100-g2d7d1b2 +# git revision 2728cb4a62a1b10b503f63d0373814d74933b21d +# git tag libsynthesis_3.4.0.16+syncevolution-1-2-2-101-g2728cb4 + +2012-06-06 Patrick Ohly + + * src/sysync/localengineds.cpp: + * src/sysync/syncsession.cpp: + * src/sysync/syncsession.h: + + SyncCap: compatibility enhancement for Nokia phones 2012-05-23 Patrick Ohly @@ -3760,553 +3768,678 @@ * src/DB_interfaces/odbc_db/odbcapiagent.h: * src/DB_interfaces/odbc_db/odbcapids.cpp: * src/syncml_tk/src/sml/mgr/all/mgrcmdbuilder.c: - * src/syncml_tk/src/sml/xlt/all/xltenc.c: - * src/sysync/binfilebase.h: - * src/sysync/binfileimplclient.cpp: - * src/sysync/binfileimplds.cpp: - * src/sysync/binfileimplds.h: - * src/sysync/customimplagent.cpp: - * src/sysync/customimplagent.h: - * src/sysync/customimplds.cpp: - * src/sysync/customimplds.h: - * src/sysync/debuglogger.cpp: - * src/sysync/debuglogger.h: - * src/sysync/itemfield.cpp: - * src/sysync/localengineds.cpp: - * src/sysync/localengineds.h: - * src/sysync/mimedirprofile.cpp: - * src/sysync/remotedatastore.cpp: - * src/sysync/rrules.cpp: - * src/sysync/scriptcontext.cpp: - * src/sysync/scriptcontext.h: - * src/sysync/stdlogicds.cpp: - * src/sysync/stdlogicds.h: - * src/sysync/stringutils.cpp: - * src/sysync/superdatastore.cpp: - * src/sysync/superdatastore.h: - * src/sysync/syncagent.cpp: - * src/sysync/syncappbase.cpp: - * src/sysync/syncclientbase.cpp: - * src/sysync/synccommand.cpp: - * src/sysync/synccommand.h: - * src/sysync/syncitemtype.cpp: - * src/sysync/syncsession.cpp: - * src/sysync/syncsession.h: - * src/sysync/sysync_globs.h: - * src/sysync/sysync_utils.cpp: - * src/sysync/timezones.cpp: - * src/sysync_SDK/DB_Interfaces/text_db/sync_dbapi_text.cpp: - * src/sysync_SDK/Sources/syerror.h: + * src/syncml_tk/src/sml/x * test/ClientTest.cpp: - comments: corrected wrong usage of english word "eventually" - throughout all sources. + testing: relaxed add<->add tests -2009-11-03 Lukas Zeller +2011-09-14 Patrick Ohly - * src/sysync/engineinterface.cpp: - * src/sysync/engineinterface.h: + * src/syncevo/Cmdline.cpp: - GetValue improved - now LOCERR_TRUNCATED also works for - VALTYPE_BUF, better description in comments + command line: also check password for + --import/export/delete-items and the source (BMC #21311, #22937) -2009-11-03 Lukas Zeller +2011-09-14 Patrick Ohly - * src/sysync/binfileimplds.cpp: - * src/sysync/binfileimplds.h: - * src/sysync/customimplds.cpp: - * src/sysync/customimplds.h: - * src/sysync/localengineds.cpp: - * src/sysync/localengineds.h: - * src/sysync/synccommand.cpp: - * src/sysync/synccommand.h: + * src/syncevo/SyncConfig.cpp: - DB specific error code: avoid showing confusing "Err = 0" and - "(DBError = 0)" texts in log and SyncML + source passwords: password lookup failed in HTTP server mode (BMC + #22937) -2009-11-03 Lukas Zeller +2011-09-12 Patrick Ohly - * src/DB_interfaces/odbc_db/odbcapids.cpp: + * src/backends/evolution/EvolutionCalendarSource.cpp: + * src/backends/evolution/EvolutionCalendarSource.h: - ODBC: bug fix: in case of datastore-level connection error, wrong - (session's) connection handle was queried for status + Evolution Calendar: fixed detached recurrence support (BMC + #22940) -2009-11-03 Lukas Zeller +2011-09-12 Patrick Ohly - * src/sysync/mimedirprofile.cpp: - * src/sysync/mimedirprofile.h: + * src/syncevo/configs/datatypes/11calendar-profile.xml: - MIME-DIR "group" feature supported now: can have - "groupfield" attribute + iCalendar 2.0: must set VALUE in EXDATE (part of BMC #22940) -2009-10-27 Lukas Zeller +2011-09-12 Patrick Ohly - * src/DB_interfaces/odbc_db/odbcapids.cpp: - * src/sysync/localengineds.cpp: + * test/testcases/eds_event.ics.memotoo.tem.patch: - Filtering: fixed stone-age (2003) bug that caused fLocalDBFilter - not to work in all cases + Memotoo testing: added EXDATEs -2009-10-27 Lukas Zeller +2011-09-12 Patrick Ohly - * src/sysync/binfileimplds.cpp: + * test/testcases/eds_event.ics: + * test/testcases/eds_event.ics.Ovi.tem.patch: + * test/testcases/eds_event.ics.funambol.tem.patch: + * test/testcases/eds_event.ics.googlecalendar.tem.patch: + * test/testcases/eds_event.ics.memotoo.tem.patch: + * test/testcases/eds_event.ics.mobical.tem.patch: + * test/testcases/eds_event.ics.nokia_7210c.tem.patch: - CRC change detection: slightly improved changelog V2/V3 -> >=V5 - migration code + testing: extended detached recurrence test cases (triggers BMC + #22940) -2009-10-27 Lukas Zeller +2011-09-13 Alban Crequy - * src/sysync/multifielditem.h: - * src/sysync/multifielditemtype.h: + * src/gtk-ui/sync-config-widget.c: - Unified "undefined field" ID definition - FID_NOT_SUPPORTED and - VARIDX_UNDEFINED have the same meaning + GTK sync-ui: wrap sync service descriptions (BMC #7199) -2009-10-27 Lukas Zeller +2011-09-13 Patrick Ohly - * src/DB_interfaces/api_db/pluginapids.cpp: + * configure-pre.in: - Comment only: DB Api - clarified use of - ContextSupport("ReadNextItem:allfields") + autotools: depend on libsynthesis with + DB_DataMerged/Replaced/Conflict support -2009-10-27 Lukas Zeller +2011-09-13 Patrick Ohly - * src/sysync/binfileimplds.cpp: - * src/sysync/binfileimplds.h: - * src/sysync/customimplds.cpp: - * src/sysync/customimplds.h: + * src/backends/akonadi/akonadisyncsource.cpp: + * src/backends/evolution/EvolutionCalendarSource.cpp: + * src/backends/evolution/EvolutionContactSource.cpp: + * src/backends/evolution/EvolutionMemoSource.cpp: + * src/backends/file/FileSyncSource.cpp: + * src/backends/webdav/CalDAVSource.cpp: + * src/backends/webdav/WebDAVSource.cpp: + * src/backends/xmlrpc/XMLRPCSyncSource.cpp: + * src/syncevo/MapSyncSource.cpp: + * src/syncevo/MapSyncSource.h: + * src/syncevo/SyncSource.cpp: + * src/syncevo/SyncSource.h: + * src/syncevo/TrackingSyncSource.cpp: + * test/ClientTest.cpp: - CRC change detection: added to enable - CRC-based change detection + SyncSource API: support and use Synthesis + DB_DataMerged/Replace/Conflict result codes (BMC #22783) -2009-10-27 Lukas Zeller +2011-09-13 Patrick Ohly - * src/sysync/mimedirprofile.cpp: - * src/sysync/mimedirprofile.h: - * src/sysync/syncsession.cpp: - * src/sysync/syncsession.h: + * test/ClientTest.cpp: + * test/ClientTest.h: - MIME-DIR, remote rules: default charset interpretation now UTF-8 - (no longer ANSI), added to override + testing: added another add<->add test -2009-10-21 Lukas Zeller +2011-08-29 Patrick Ohly - * src/sysync/customimplds.cpp: + * src/syncevo/SyncSource.cpp: + * test/ClientTest.cpp: + * test/ClientTest.h: - DB mapping: added to allow specifying details for - ped fields + testing: added test case for add<->add conflict (part of BMC + #22783) -2009-10-26 Beat Forster +2011-09-14 Patrick Ohly - * src/sysync_SDK/Sources/SDK_util.c: - * src/sysync_SDK/Sources/generic_types.h: - * src/sysync_SDK/Sources/sync_dbapidef.h: + * src/syncevo/SyncContext.cpp: - Plain C does not allow // as comment + source configs: don't check "backend" unless it is needed -2009-10-22 Lukas Zeller +2011-09-13 Patrick Ohly - * src/sysync/scriptcontext.cpp: + * test/dbus-session.sh: - scripts: variable definitions only shown with SYDEBUG>1 + dbus-session: adapted EDS startup to 3.2 -2009-10-13 Beat Forster +2011-09-07 Patrick Ohly - * src/DB_interfaces/api_db/DLL_interface.cpp: - * src/DB_interfaces/api_db/sync_dbapiconnect.cpp: - * src/platform_adapters/linux/configfiles.cpp: - * src/sysync/sysync.h: - * src/sysync/sysync_globs.h: - * src/sysync_SDK/Sources/SDK_util.c: - * src/sysync_SDK/Sources/UI_util.cpp: - * src/sysync_SDK/Sources/sync_dbapi.h: - * src/sysync_SDK/Sources/sync_dbapidef.h: - * src/sysync_SDK/Sources/sync_include.h: + * test/ClientTest.cpp: - Adaptations for Android + client-test: remove duplicate CLIENT_TEST_LOG support code -2009-10-21 Beat Forster +2011-09-06 Patrick Ohly - * src/sysync_SDK/Sources/dbitem.cpp: + * test/ClientTest.cpp: - dbitem (SDK_textdb) missing fChanged= true added + testing: fix Client::Sync::*::testLinkedItemsChildParent -2009-10-17 Lukas Zeller +2011-09-05 Patrick Ohly - * src/sysync/syncagent.cpp: - * src/sysync/syncagent.h: - * src/sysync/synccommand.cpp: - * src/sysync/synccommand.h: - * src/sysync/syncsession.cpp: - * src/sysync/syncsession.h: + * test/ClientTest.cpp: - Alert 222 loop detector improved: do not trigger as long as valid - status is received + testing: fix m_uniqueProperties check -2009-10-16 Lukas Zeller +2011-09-02 Patrick Ohly - * src/DB_interfaces/odbc_db/odbcapiagent.cpp: + * src/backends/addressbook/AddressBookSourceRegister.cpp: + * src/backends/akonadi/AkonadiSyncSourceRegister.cpp: + * src/backends/evolution/EvolutionCalendarSourceRegister.cpp: + * src/backends/evolution/EvolutionContactSourceRegister.cpp: + * src/backends/file/FileSyncSourceRegister.cpp: + * src/backends/kcalextended/KCalExtendedSourceRegister.cpp: + * src/backends/maemo/MaemoCalendarSourceRegister.cpp: + * src/backends/qtcontacts/QtContactsSourceRegister.cpp: + * src/backends/sqlite/SQLiteContactSourceRegister.cpp: + * src/backends/webdav/WebDAVSourceRegister.cpp: + * src/client-test-app.cpp: + * src/syncevo/Cmdline.h: + * src/syncevo/SyncContext.cpp: + * src/syncevo/SyncContext.h: + * src/syncevo/SyncSource.h: + * src/syncevo/util.h: + * src/syncevolution.cpp: + * test/ClientTest.cpp: + * test/ClientTest.h: - ODBC STD servers and clients: did not work at all (connection - string always empty) + testing: cleaned up ClientTestConfig -2009-10-16 Lukas Zeller +2011-09-01 Patrick Ohly - * src/sysync/engineinterface.cpp: - * src/sysync_SDK/Sources/sync_dbapidef.h: + * test/ClientTest.cpp: - comment cosmetics + client-test + ActiveSync: ignore Exchange failure in + testLinkedItemsRemoveNormal -2009-10-15 Lukas Zeller +2011-09-01 Patrick Ohly - * src/sysync/mimedirprofile.cpp: + * test/ClientTest.cpp: - vcard/vcal folding: Made sure folding does not occur within UTF-8 - sequences + client-test: wrap compareDatabases() in CPPUNIT_ASSERT_NO_THROW() -2009-10-15 Lukas Zeller +2011-09-01 Patrick Ohly - * src/sysync/mimedirprofile.cpp: - * src/sysync/sysync_utils.cpp: + * test/ClientTest.cpp: - vcard/vcal B64 properties: base64 encoded properties must be - terminated with a CRLF even if folding is disabled + client-test LinkedItems: use CLIENT_TEST_LINKED_ITEMS_NO_DELETE + to stop test early -2009-10-14 Lukas Zeller +2011-09-01 Patrick Ohly - * src/sysync/mimedirprofile.cpp: + * test/ClientTest.cpp: - vcard/vcal B64 properties: added workaround to recognize - improperly folded B64 properties + client-test: cleaned up checking for CLIENT_TEST_SERVER -2009-10-13 Lukas Zeller +2011-08-30 Patrick Ohly - * src/DB_interfaces/api_db/pluginapids.cpp: - * src/sysync/localengineds.cpp: - * src/sysync/multifielditem.cpp: - * src/sysync/stdlogicds.cpp: - * src/sysync/syncagent.cpp: - * src/sysync/syncsession.cpp: + * src/backends/akonadi/configure-sub.in: - unilib: eliminated another bunch of printf argument warnings by - casting all %ld arguments to (long) + Akonadi: fix link issues on Debian Testing -2009-10-13 Lukas Zeller +2011-08-30 Patrick Ohly - * src/sysync/engineinterface.cpp: + * src/NotificationBackendLibnotify.cpp: - engineinterface: added missing return statement for - returnLineartime() + NotifyBackendLibnotify: avoid compiler warning about unused + NotFound() -2009-10-08 Beat Forster +2011-08-29 Patrick Ohly - * src/sysync/customimplds.cpp: + * src/NotificationBackendLibnotify.cpp: - stl_minimal has no != operator => use == + syncevolution.org binaries: fix libnotify compatibility mode, + part II (BMC #22668) -2009-10-08 Beat Forster +2011-08-29 Patrick Ohly - * src/global_options.h: - * src/platform_adapters/linux/configfiles.cpp: + * test/ClientTest.cpp: - ANDROID strings added + testing: LinkedItems_1 with "exchange" server: recurring all-day + event -2009-10-08 Beat Forster +2011-08-29 Patrick Ohly - * src/DB_interfaces/api_db/pluginapids.cpp: - * src/DB_interfaces/odbc_db/odbcapiagent.cpp: - * src/sysync/syncagent.cpp: - * src/sysync_SDK/Sources/stringutil.cpp: + * test/ClientTest.cpp: - unilib: several type adaptions for changes due to unilib + testing: modify LinkedItems test data for Exchange -2009-10-13 Lukas Zeller +2011-08-29 Patrick Ohly + * src/syncevo/SyncSource.h: + * test/ClientTest.cpp: - Merge remote branch 'moblin/unilib' into unilib + testing: introduced ClientTestConfig::sourceLUIDsAreVolatile -2009-10-13 Lukas Zeller +2011-08-27 Patrick Ohly - * src/sysync/syncclientbase.cpp: + * test/testcases/eds_event.ics.funambol.tem.patch: - unilib: make sure no half-constructed session is left over at - failed OpenSession() + testing: avoid Funambol eds_event::testItems failure -2009-10-08 Lukas Zeller +2011-09-13 Patrick Ohly - * src/DB_interfaces/api_db/pluginapids.cpp: - * src/sysync/customimplagent.cpp: - * src/sysync/customimplds.cpp: - * src/sysync/syncsession.cpp: + * test/dbus-session.sh: - unilib cleanup: fixed some build problems introduced through - unilib + dbus-session: adapted EDS startup to 3.2 -2009-10-08 Lukas Zeller +2011-09-13 Patrick Ohly - * src/DB_interfaces/odbc_db/odbcapiagent.cpp: - * src/sysync/customimplagent.h: + * configure.ac: - unilib: fixed case for targets with no binfile compiled in at all + autotools: updated warning flags -2009-10-07 Lukas Zeller +2011-09-13 Patrick Ohly - * src/sysync/syserial.h: + * src/dbus/interfaces/syncevo-server-full.xml: - syserial product codes: added codes for Android client and server - libs, changed Win32 server code (was overlapping iPhone client - lib) + D-Bus: fixed compile problem due to <> in XML text -2009-10-07 Beat Forster +2011-09-12 Patrick Ohly - * src/sysync_SDK/Sources/SDK_util.c: - * src/sysync_SDK/Sources/sync_dbapidef.h: + * src/backends/activesync/README: - SDK: version changed to V1.6.1 + ActiveSync README: added remark about shared target config -2009-10-13 Lukas Zeller +2011-09-07 Patrick Ohly - * src/sysync/engineinterface.cpp: - * src/sysync/engineinterface.h: - * src/sysync/syncagent.cpp: + * src/backends/activesync/ActiveSyncCalendarSource.cpp: + * src/backends/activesync/ActiveSyncSource.cpp: - engine: added "lastused" and "timeout" session keys for server - session timeout handling + ActiveSync: added logging of sync key handling -2009-10-12 Patrick Ohly +2011-09-07 Patrick Ohly - * src/gen-makefile-am.sh: + * test/ClientTest.cpp: - autotools build: only build SAN code as part of the SDK + client-test: remove duplicate CLIENT_TEST_LOG support code -2009-10-08 Lukas Zeller +2011-09-06 Patrick Ohly + * test/ClientTest.cpp: - Merge remote branch 'moblin/unilib' into unilib + testing: fix Client::Sync::*::testLinkedItemsChildParent -2009-10-08 Lukas Zeller +2011-09-06 Patrick Ohly + * src/dbus/interfaces/syncevo-server-full.xml: + * src/dbus/server/read-operations.cpp: + * src/dbus/server/session.cpp: + * src/syncevo/SyncConfig.h: - Merge branch 'luz' into unilib + D-Bus server: send hardware info in new "hardwareName" read-only + property -2009-10-08 Lukas Zeller +2011-08-29 Chris Kühl + * test/bluetooth-device-id-inspector.py: - Merge remote branch 'moblin/san' into luz + Add script to query for the bluetooth device id -2009-10-07 Lukas Zeller +2011-08-29 Chris Kühl + * src/dbus/server/read-operations.cpp: + * src/syncevo/SyncConfig.cpp: + * src/syncevo/SyncConfig.h: - Merge branch 'luz' into unilib + Make deviceName and peerName more well-defined. -2009-10-07 Beat Forster +2011-09-06 Patrick Ohly - * src/platform_adapters/linux/configfiles.cpp: - * src/platform_adapters/linux/platform_time.cpp: + * test/testcases/eds_contact.vcf.exchange.tem.patch: - platform adapters Linux: Android adaptions + testing: Exchange contact test cases -2009-10-07 Lukas Zeller +2011-09-05 Patrick Ohly - * src/sysync/localengineds.cpp: + * test/ClientTest.cpp: - localengineds: avoid using != operator on strings because STLs - exist that only support == + testing: fix m_uniqueProperties check -2009-10-07 Patrick Ohly +2011-09-02 Patrick Ohly - * Makefile.am: - * configure.in: - * src/Makefile.am.in: - * src/gen-makefile-am.sh: - * src/sysync_SDK/Sources/enginestubs.c: - * synthesis-sdk.pc.in: - * synthesis.pc.in: + * src/src.am: + * src/syncevo/configs/configs_xml.am: + * src/templates/templates.am: - autotools + pkg-config: added synthesis-sdk.pc + autotools: fixed "make dist[check]" in non-recursive Automake -2009-10-02 Patrick Ohly +2011-09-02 Patrick Ohly - * src/Makefile.am.in: + * src/backends/activesync/ActiveSyncSourceRegister.cpp: + * src/backends/addressbook/AddressBookSourceRegister.cpp: + * src/backends/akonadi/AkonadiSyncSourceRegister.cpp: + * src/backends/evolution/EvolutionCalendarSourceRegister.cpp: + * src/backends/evolution/EvolutionContactSourceRegister.cpp: + * src/backends/file/FileSyncSourceRegister.cpp: + * src/backends/kcalextended/KCalExtendedSourceRegister.cpp: + * src/backends/maemo/MaemoCalendarSourceRegister.cpp: + * src/backends/qtcontacts/QtContactsSourceRegister.cpp: + * src/backends/sqlite/SQLiteContactSourceRegister.cpp: + * src/backends/webdav/WebDAVSourceRegister.cpp: + * src/client-test-app.cpp: + * src/syncevo/Cmdline.h: + * src/syncevo/SyncContext.cpp: + * src/syncevo/SyncContext.h: + * src/syncevo/SyncSource.h: + * src/syncevo/util.h: + * src/syncevolution.cpp: + * test/ClientTest.cpp: + * test/ClientTest.h: - libsynthesis + autotools: must be linked against libz + testing: cleaned up ClientTestConfig -2009-10-07 Patrick Ohly +2011-09-02 Patrick Ohly - * src/sysync/syncappbase.cpp: + * src/gdbus/gdbus-cxx-bridge.cpp: + * src/gdbus/gdbus-cxx-bridge.h: - syncappbasse: turned extern "C" into static functions + GDBusCXX: fix boost::intrusive_ptr compile problem with clang -2009-10-02 Patrick Ohly +2011-09-01 Patrick Ohly - * configure.in: - * src/Makefile.am.in: - * src/gen-makefile-am.sh: - * src/synthesis-linker.map: - * src/sysync_SDK/Sources/UI_util.cpp: + * src/backends/addressbook/addressbook.am: - autotools build: switched to new combi engine + autotools: removed obsolete MAINTAINERCLEANFILES -2009-10-07 Patrick Ohly +2011-09-01 Patrick Ohly - * src/sysync/dataconversion.cpp: + * test/testcases/eds_event.ics.exchange.tem.patch: - DataConversion(): adapted dummy engine to server API + Exchange event testing: special testcases -2009-09-24 Patrick Ohly +2011-09-01 Patrick Ohly - * configure.in: - * src/sysync/san.cpp: - * src/sysync/san.h: - * src/sysync/sysync_b64.cpp: - * src/sysync/sysync_b64.h: - * src/sysync/sysync_md5.cpp: - * src/sysync/sysync_md5.h: - * src/sysync_SDK/Sources/san.cpp: - * src/sysync_SDK/Sources/san.h: - * src/sysync_SDK/Sources/sysync_b64.cpp: - * src/sysync_SDK/Sources/sysync_b64.h: - * src/sysync_SDK/Sources/sysync_md5.cpp: - * src/sysync_SDK/Sources/sysync_md5.h: + * src/backends/activesync/ActiveSyncCalendarSource.cpp: - SAN: moved to SDK, together with the corresponding utility - classes + ActiveSync: fixed "merge" detection in case of fast path -2009-10-03 Lukas Zeller +2011-09-01 Patrick Ohly - * src/Targets/ReleasedProducts/combiEngine_opensource_linux/combiengine_opensource_linux_prefix.h: + * src/backends/activesync/ActiveSyncSourceRegister.cpp: - unilib linux compile: corrected include (no separate combi-engine - include file exists here) + client-test + ActiveSync: avoid tests which depend on storing + detached children alone -2009-10-03 Lukas Zeller +2011-09-01 Patrick Ohly - * src/client_engine_linux.mk: - * src/combi_engine_linux.mk: - * src/server_engine_linux.mk: + * test/ClientTest.cpp: - unilib: added plain makefile for combined client+server engine, - adapted client-only and server-only to use syncagent.h/.cpp + client-test + ActiveSync: ignore Exchange failure in + testLinkedItemsRemoveNormal -2009-10-03 Lukas Zeller +2011-09-01 Patrick Ohly - * src/sysync/syncclient.cpp: - * src/sysync/syncclient.h: - * src/sysync/syncserver.cpp: - * src/sysync/syncserver.h: + * test/ClientTest.cpp: - unilib: removed now obsolete syncclient/syncserver files + client-test: wrap compareDatabases() in CPPUNIT_ASSERT_NO_THROW() -2009-10-03 Lukas Zeller +2011-09-01 Patrick Ohly + * test/ClientTest.cpp: - Merge branch 'luz' into unilib + client-test LinkedItems: use CLIENT_TEST_LINKED_ITEMS_NO_DELETE + to stop test early -2009-10-03 Lukas Zeller +2011-09-01 Patrick Ohly - * src/sysync_SDK/Sources/UI_util.cpp: + * test/ClientTest.cpp: - engine entry points: adjusted as per discussion (Patrick/bfo) + client-test: cleaned up checking for CLIENT_TEST_SERVER -2009-10-01 Patrick Ohly +2011-09-01 Patrick Ohly - * src/sysync_SDK/Sources/UI_util.cpp: - * src/sysync_SDK/Sources/UI_util.h: - * src/sysync_SDK/Sources/enginemodulebridge.cpp: - * src/sysync_SDK/Sources/enginemodulebridge.h: + * src/syncevo/GLibSupport.h: - SDK engine connect: allow choosing between client and server - engine + GLibSupport + ActiveSync: fixed compiler warning -2009-10-01 Patrick Ohly +2011-08-31 Patrick Ohly - * src/platform_adapters/linux/platform_DLL.cpp: + * src/backends/activesync/activesync.am: + * src/backends/activesync/configure-sub.in: - Linux platform_DLL: open shared library with name as requested + autotools: improved ActiveSync rules -2009-10-01 Patrick Ohly +2011-08-31 Patrick Ohly - * src/sysync/engineentry.h: - * src/sysync_SDK/Sources/sync_dbapidef.h: + * src/backends/webdav/webdav.am: - use ENGINE_ENTRY_CXX to mark external C++ functions + autotools: fixed building of syncevo-webdav-lookup -2009-10-01 Patrick Ohly +2011-08-31 Patrick Ohly - * src/sysync/dataobjtype.cpp: + * configure.ac: - added "namespace sysync" + autotools: allow --enable-warnings=fatal -2009-09-27 Patrick Ohly +2011-08-31 Patrick Ohly - * src/Makefile.am.in: - * src/gen-makefile-am.sh: + * test/runtests.py: - autotools: added make rules for server engine - (libsynthesisserver.so) + runtest.py: adapted to non-recursive Automake -2009-10-03 Lukas Zeller +2011-08-31 Patrick Ohly + * src/backends/activesync/Makefile.am: + * src/backends/activesync/activesync.am: + * src/backends/activesync/configure-sub.in: - Merge remote branch 'origin/bfo' into luz + ActiveSync: ported to non-recursive Automake -2009-09-27 Patrick Ohly +2011-08-30 Krzesimir Nowak - * src/sysync/syncsession.cpp: + * AUTOTOOLS-TODO: + + Updated AUTOTOOLS-TODO. + +2011-08-30 Krzesimir Nowak + + * .cvsignore: + * .gitignore: + * AUTOTOOLS-TESTING: + * AUTOTOOLS-TODO: + * INSTALL: + * Makefile.am: + * README.packagers: + * autogen.sh: + * autotroll.am: + * build/build.am: + * build/gen-backends-am.sh: + * build/gen-backends.sh: + * build/gen-git-version.sh: + * build/gen-linguas.sh: + * configure-post.in: + * configure-pre.in: + * configure.ac: + * gen-autotools.sh: + * m4-repo/autotroll.mk: + * m4-repo/dk-warn.m4: + * m4-repo/se_macros.m4: + * po/.gitignore: + * po/LINGUAS.README: + * setup-variables.am: + * src/.cvsignore: + * src/.gitignore: + * src/Makefile-gen.am: + * src/backends/addressbook/Makefile.am: + * src/backends/addressbook/addressbook.am: + * src/backends/addressbook/configure-sub.in: + * src/backends/akonadi/Makefile.am: + * src/backends/akonadi/akonadi.am: + * src/backends/akonadi/configure-sub.in: + * src/backends/buteo/Makefile.am: + * src/backends/buteo/buteo.am: + * src/backends/buteo/configure-sub.in: + * src/backends/buteo/profiles/profiles.am: + * src/backends/evolution/Makefile.am: + * src/backends/evolution/configure-sub.in: + * src/backends/evolution/evolution.am: + * src/backends/file/Makefile.am: + * src/backends/file/configure-sub.in: + * src/backends/file/file.am: + * src/backends/kcalextended/Makefile.am: + * src/backends/kcalextended/configure-sub.in: + * src/backends/kcalextended/kcalextended.am: + * src/backends/maemo/Makefile.am: + * src/backends/maemo/configure-sub.in: + * src/backends/maemo/maemo.am: + * src/backends/qtcontacts/Makefile.am: + * src/backends/qtcontacts/configure-sub.in: + * src/backends/qtcontacts/qtcontacts.am: + * src/backends/sqlite/Makefile.am: + * src/backends/sqlite/configure-sub.in: + * src/backends/sqlite/sqlite.am: + * src/backends/webdav/Makefile.am: + * src/backends/webdav/configure-sub.in: + * src/backends/webdav/webdav.am: + * src/backends/xmlrpc/Makefile.am: + * src/backends/xmlrpc/configure-sub.in: + * src/backends/xmlrpc/xmlrpc.am: + * src/dbus/.gitignore: + * src/dbus/Makefile.am: + * src/dbus/dbus.am: + * src/dbus/glib/Makefile.am: + * src/dbus/glib/glib.am: + * src/dbus/interfaces/Makefile.am: + * src/dbus/interfaces/interfaces.am: + * src/dbus/qt/Makefile.am: + * src/dbus/qt/configure-sub.in: + * src/dbus/qt/qt.am: + * src/dbus/server/.gitignore: + * src/dbus/server/Makefile.am: + * src/dbus/server/server.am: + * src/gdbus/.gitignore: + * src/gdbus/Makefile.am: + * src/gdbus/gdbus.am: + * src/gnome-bluetooth/Makefile.am: + * src/gnome-bluetooth/gnome-bluetooth.am: + * src/gtk-ui/Makefile.am: + * src/gtk-ui/gtk-ui.am: + * src/src.am: + * src/syncevo/.gitignore: + * src/syncevo/Makefile.am: + * src/syncevo/SingleFileConfigTree.h: + * src/syncevo/SoupTransportAgent.cpp: + * src/syncevo/configs/Makefile.am: + * src/syncevo/configs/configs.am: + * src/syncevo/configs/configs_xml.am: + * src/syncevo/syncevo.am: + * src/syncevo/syncevolution.pc.in: + * src/templates/templates.am: + * src/testcases.am: + * test/Makefile.am: + * test/run_src_client_test.sh: + * test/test-dbus.py: + * test/test.am: - TSyncSession: unitialized fEncoding + Port build system to non-recursive Automake. -2009-10-03 Lukas Zeller +2011-08-30 Patrick Ohly + * build/import-foreign-git.sh: - Merge remote branch 'moblin/master' into luz + import-foreign-git.sh: added interactive patch fixing -2009-10-03 Lukas Zeller +2011-08-30 Patrick Ohly - * src/Targets/ReleasedProducts/combiEngine_opensource_linux/combiengine_demo++.pch: - * src/Targets/ReleasedProducts/combiEngine_opensource_linux/combiengine_demo.pch: - * src/Targets/ReleasedProducts/combiEngine_opensource_linux/combiengine_opensource_linux_prefix.h: - * src/Targets/ReleasedProducts/combiEngine_opensource_linux/define.h: - * src/Targets/ReleasedProducts/combiEngine_opensource_linux/target_options.h: + * src/dbus/server/NotificationBackendLibnotify.cpp: - opensource linux combiengine: added new target files + NotifyBackendLibnotify: avoid compiler warning about unused + NotFound() -2009-10-02 Lukas Zeller +2011-08-30 Patrick Ohly - * src/DB_interfaces/api_db/pluginapiagent.cpp: - * src/DB_interfaces/api_db/pluginapiagent.h: - * src/DB_interfaces/odbc_db/odbcapiagent.cpp: - * src/Transport_interfaces/engine/engineclientbase.cpp: - * src/Transport_interfaces/engine/engineclientbase.h: - * src/Transport_interfaces/engine/enginesessiondispatch.cpp: - * src/Transport_interfaces/engine/enginesessiondispatch.h: - * src/syncapps/serverEngine_custom/serverengine_custom_Base.cpp: - * src/sysync/localengineds.cpp: - * src/sysync/localengineds.h: - * src/sysync/stdlogicagent.h: - * src/sysync/stdlogicds.cpp: - * src/sysync/superdatastore.cpp: - * src/sysync/superdatastore.h: - * src/sysync/syncagent.cpp: - * src/sysync/syncagent.h: - * src/sysync/syncappbase.cpp: - * src/sysync/syncappbase.h: - * src/sysync/syncclientbase.cpp: - * src/sysync/synccommand.cpp: - * src/sysync/synccommand.h: - * src/sysync/syncdatastore.cpp: - * src/sysy * src/backends/activesync/ActiveSyncCalendarSource.cpp: + * src/backends/akonadi/configure-sub.in: + + Akonadi: fix link issues on Debian Testing + +2011-08-30 Patrick Ohly + + * src/backends/activesync/Makefile.am: + * src/backends/activesync/README: + * src/backends/activesync/configure-sub.in: + + ActiveSync: enabled compilation + +2011-08-29 Patrick Ohly + + * src/backends/activesync/ActiveSyncSourceRegister.cpp: + + ActiveSync: set "sourceLUIDsAreVolatile" + +2011-08-15 Patrick Ohly + + * src/backends/activesync/README: + + ActiveSync: use target-config@client-test-exchange for + Client::Source + +2011-08-12 Patrick Ohly + + * src/backends/activesync/ActiveSyncCalendarSource.cpp: + * src/backends/activesync/ActiveSyncSource.cpp: + + ActiveSync: check for unexpected NULL pointers (BMC #22048) + +2011-08-12 Patrick Ohly + + * src/backends/activesync/ActiveSyncCalendarSource.cpp: + * src/backends/activesync/ActiveSyncSource.cpp: + + ActiveSync: also support moreAvailable in calendar source + +2011-08-01 Salvatore Iovene + + * src/backends/activesync/ActiveSyncSource.cpp: + + ActiveSync: allow retrieval of items beyond the single-call + window. + +2011-08-12 Patrick Ohly + + * src/backends/activesync/ActiveSyncSource.cpp: + + ActiveSync: check for NULL result from eas_sync_handler_new() + +2011-08-12 Patrick Ohly + + * src/backends/activesync/README: + + ActiveSync: include syncURL in README + +2011-08-03 Patrick Ohly + + * src/backends/activesync/README: + + ActiveSync: updated README + +2011-08-01 Patrick Ohly + + * src/backends/activesync/ActiveSyncCalendarSource.cpp: + + ActiveSync: must retrieve existing item before updating it + +2011-07-28 Patrick Ohly + + * src/backends/activesync/ActiveSyncCalendarSource.h: + * src/backends/activesync/ActiveSyncSourceRegister.cpp: + + ActiveSync: improved testImport for ActiveSyncCalendarSource + +2011-07-28 Patrick Ohly + + * src/backends/activesync/ActiveSyncSource.h: + * src/backends/activesync/ActiveSyncSourceRegister.cpp: + + ActiveSync: fixed testImport test + +2011-07-28 Patrick Ohly + + * src/backends/activesync/ActiveSyncSource.cpp: + + ActiveSync: read existing items with + eas_sync_handler_fetch_item() + +2011-07-26 Patrick Ohly + + * src/backends/activesync/ActiveSyncCalendarSource.cpp: * src/backends/activesync/ActiveSyncCalendarSource.h: * src/backends/activesync/ActiveSyncSource.cpp: * src/backends/activesync/ActiveSyncSource.h: * src/backends/activesync/ActiveSyncSourceRegister.cpp: - ActiveSync: map multiple VEVENTs with th * src/syncapps/clientEngine_custom/product_options.h: - * src/syncapps/serverEngine_custom/comb * src/backends/activesync/ActiveSyncSource.cpp: + ActiveSync: map multiple VEVENTs with the same UID into the same + ActiveSync item + +2011-07-11 Patrick Ohly + + * src/backends/activesync/ActiveSyncSource.cpp: * src/backends/activesync/ActiveSyncSource.h: - * src/backends/ac * src/DB_interfaces/odbc_db/odbcapiagent.cpp: - * src/DB_interfaces/odbc_db/odbcapids.cpp: - * src/Transport_interfaces/engine/enginesessiondispatch.cpp: - * src/platform_adapt * src/backends/activesync/ActiveSyncSourceRegister.cpp: + * src/backends/activesync/ActiveSyncSourceRegister.cpp: + * src/backends/activesync/README: + + ActiveSync: fixed change tracking in testing + +2011-07-08 Patrick Ohly + + * src/backends/activesync/ActiveSyncSourceRegister.cpp: * src/backends/activesync/README: ActiveSync: enable client-test testing diff --git a/src/synthesis/src/sysync/localengineds.cpp b/src/synthesis/src/sysync/localengineds.cpp index 09ad433..ce3d034 100644 --- a/src/synthesis/src/sysync/localengineds.cpp +++ b/src/synthesis/src/sysync/localengineds.cpp @@ -3784,26 +3784,45 @@ SmlDevInfSyncCapPtr_t TLocalEngineDS::newDevInfSyncCap(uInt32 aSyncCapMask) // Now add non-standard synccaps. // From the spec: "Other values can also be specified." // Values are PCDATA, so we can use plain strings. + // // But the Funambol server expects integer numbers and // throws a parser error when sent a string. So better // stick to a semi-random number (hopefully no-one else // is using it). // + // Worse, Nokia phones cancel direct sync sessions with an + // OBEX error ("Forbidden") when non-standard sync modes + // are included in the SyncCap. As a workaround for that + // we use the following logic: + // - libsynthesis in a SyncML client will always send + // all the extended sync modes; with the Funambol + // workaround in place that works + // - libsynthesis in a SyncML server will only send the + // extended sync modes if the client has sent any + // extended sync modes itself; the 390002 mode is + // sent unconditionally for that purpose + // // Corresponding code in TRemoteDataStore::setDatastoreDevInf(). - if (canRestart()) { - synctypeP=newPCDataString("390001"); + // + if (!IS_SERVER || + fSessionP->receivedSyncModeExtensions()) { + if (canRestart()) { + synctypeP=newPCDataString("390001"); + addPCDataToList(synctypeP,&(synccapP->synctype)); + } + synctypeP=newPCDataString("390002"); addPCDataToList(synctypeP,&(synccapP->synctype)); - } - // Finally add non-standard synccaps that are outside of the - // engine's control. - set modes; - getSyncModes(modes); - for (set::const_iterator it = modes.begin(); - it != modes.end(); - ++it) { - synctypeP=newPCDataString(*it); - addPCDataToList(synctypeP,&(synccapP->synctype)); + // Finally add non-standard synccaps that are outside of the + // engine's control. + set modes; + getSyncModes(modes); + for (set::const_iterator it = modes.begin(); + it != modes.end(); + ++it) { + synctypeP=newPCDataString(*it); + addPCDataToList(synctypeP,&(synccapP->synctype)); + } } // return it diff --git a/src/synthesis/src/sysync/syncsession.cpp b/src/synthesis/src/sysync/syncsession.cpp index 074abce..f71a2a0 100644 --- a/src/synthesis/src/sysync/syncsession.cpp +++ b/src/synthesis/src/sysync/syncsession.cpp @@ -5890,6 +5890,41 @@ TLocalDSConfig *TSessionConfig::newDatastoreConfig(const char *aName, const char #endif // HARDCODED_CONFIG +bool TSyncSession::receivedSyncModeExtensions() +{ + TRemoteDataStorePContainer::iterator pos; + for (pos=fRemoteDataStores.begin(); pos!=fRemoteDataStores.end(); ++pos) { + set modes; + (*pos)->getSyncModes(modes); + set::const_iterator it; + for (it=modes.begin(); it!=modes.end(); ++it) { + const char *nptr = it->c_str(); + char *endptr; + if (!*nptr) { + // ignore empty mode + continue; + } + long mode = strtol(nptr, &endptr, 10); + // ignore trailing spaces + while (isspace(*endptr)) { + endptr++; + } + if (*endptr) { + // non-standard character => found extensions + return true; + } + + if (mode > 32) { + // Non-standed integer code! + // Choosing 32 is somewhat random, not all of those + // are really defined in the standard. + return true; + } + } + } + return false; +} + } // namespace sysync #endif // not SYNCSESSION_PART1_EXCLUDE diff --git a/src/synthesis/src/sysync/syncsession.h b/src/synthesis/src/sysync/syncsession.h index 6fa780b..fe882a3 100755 --- a/src/synthesis/src/sysync/syncsession.h +++ b/src/synthesis/src/sysync/syncsession.h @@ -728,6 +728,8 @@ protected: TLocalDataStorePContainer fLocalDataStores; // - list of remote (client-side) datastores TRemoteDataStorePContainer fRemoteDataStores; + bool receivedSyncModeExtensions(); // any of the remote datastores in fRemoteDataStores + // had custom sync modes // - list of local content types TSyncItemTypePContainer fLocalItemTypes; // - list of remote item types diff --git a/test/ClientTest.cpp b/test/ClientTest.cpp index 9b3afa1..1aabba0 100644 --- a/test/ClientTest.cpp +++ b/test/ClientTest.cpp @@ -280,7 +280,12 @@ public: } } - void reset(TestingSyncSource *source = NULL) + enum Flags { + SLOW, /**< erase anchor, start accessing database from scratch */ + INCREMENTAL /**< allow source to do incremental data read */ + }; + + void reset(TestingSyncSource *source = NULL, Flags flags = INCREMENTAL) { if (get() && m_active) { stopAccess(); @@ -291,7 +296,7 @@ public: base_t::reset(source); } if (source) { - startAccess(); + startAccess(flags); } } @@ -299,7 +304,7 @@ public: * done automatically as part of reset(), only to be called * after an explicit stopAccess() */ - void startAccess() + void startAccess(Flags flags = INCREMENTAL) { CT_ASSERT(get()); CT_ASSERT(!m_active); @@ -311,6 +316,9 @@ public: CT_ASSERT_NO_THROW(get()->open()); string node = get()->getTrackingNode()->getName(); string anchor = m_anchors[node]; + if (flags == SLOW) { + anchor = ""; + } get()->beginSync(anchor, ""); if (isServerMode()) { CT_ASSERT_NO_THROW(get()->enableServerMode()); @@ -1282,9 +1290,13 @@ void LocalTests::testImport() { backupStorage(config, client); CT_ASSERT_NO_THROW(source.reset()); - // export again and compare against original file + // export again and compare against original file, + // without relying on change tracking (because + // Google ActiveSync has problems with Fetch, + // which would be needed for a data dump when + // using the incremental approach) TestingSyncSourcePtr copy; - SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceA())); + SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceA(), TestingSyncSourcePtr::SLOW)); bool equal = compareDatabases(testcases.c_str(), *copy.get(), false); CT_ASSERT_NO_THROW(source.reset()); @@ -1371,7 +1383,7 @@ void LocalTests::testRemoveProperties() { // compare TestingSyncSourcePtr copy; - SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceA())); + SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceA(), TestingSyncSourcePtr::SLOW)); bool equal = compareDatabases(updated.c_str(), *copy.get(), false); CT_ASSERT_NO_THROW(source.reset()); @@ -5596,8 +5608,8 @@ static bool setDeadSyncURL(SyncContext &context, FullProps props = context.getConfigProps(); string target = url.substr(strlen("local://")); props[target].m_syncProps["syncURL"] = fakeURL; - props[target].m_syncProps["retryDuration"] = "10"; - props[target].m_syncProps["retryInterval"] = "10"; + props[target].m_syncProps["retryDuration"] = InitStateString("10", true); + props[target].m_syncProps["retryInterval"] = InitStateString("10", true); context.setConfigProps(props); return false; } else { diff --git a/test/synccompare.pl b/test/synccompare.pl index 470e5e8..0417b7a 100644 --- a/test/synccompare.pl +++ b/test/synccompare.pl @@ -84,7 +84,9 @@ my $full_timezones = $ENV{CLIENT_TEST_FULL_TIMEZONES}; # do not simplify VTIMEZO my $exchange = $server =~ /exchange/; # Exchange via ActiveSync my $egroupware = $server =~ /egroupware/; my $funambol = $server =~ /funambol/; -my $google = $server =~ /google/; +my $googlesyncml = $server eq "google"; +my $googlecaldav = $server eq "googlecalendar"; +my $googleeas = $server eq "googleeas"; my $google_valarm = $ENV{CLIENT_TEST_GOOGLE_VALARM}; my $yahoo = $server =~ /yahoo/; my $davical = $server =~ /davical/; @@ -363,7 +365,7 @@ sub NormalizeItem { # > LY s/^(\w+)([^:\n]*);X-EVOLUTION-ENDDATE=[0-9TZ]*/$1$2/mg; - if ($scheduleworld || $egroupware || $synthesis || $addressbook || $funambol ||$google || $mobical || $memotoo) { + if ($scheduleworld || $egroupware || $synthesis || $addressbook || $funambol ||$googlesyncml || $googleeas || $mobical || $memotoo) { # does not preserve X-EVOLUTION-UI-SLOT= s/^(\w+)([^:\n]*);X-EVOLUTION-UI-SLOT=\d+/$1$2/mg; } @@ -389,7 +391,7 @@ sub NormalizeItem { s/^(TEL.*);TYPE=PREF/$1/mg; } - if($google) { + if($googlesyncml) { # ignore the PHOTO encoding data s/^PHOTO(.*?): .*\n/^PHOTO$1: [...]\n/mg; # FN propertiey is not correct @@ -398,7 +400,9 @@ sub NormalizeItem { s!^TEL\;TYPE=CAR(.*)\n!TEL$1\n!mg; # some properties are lost s/^(X-EVOLUTION-FILE-AS|NICKNAME|BDAY|CATEGORIES|CALURI|FBURL|ROLE|URL|X-AIM|X-EVOLUTION-UI-SLOT|X-ANNIVERSARY|X-ASSISTANT|X-EVOLUTION-BLOG-URL|X-EVOLUTION-VIDEO-URL|X-GROUPWISE|X-ICQ|X-GADUGADU|X-JABBER|X-MSN|X-SIP|X-SKYPE|X-MANAGER|X-SPOUSE|X-MOZILLA-HTML|X-YAHOO)(;[^:;\n]*)*:.*\r?\n?//gm; + } + if ($googlecaldav) { #several properties are not preserved by Google in icalendar2.0 format s/^(SEQUENCE|X-EVOLUTION-ALARM-UID)(;[^:;\n]*)*:.*\r?\n?//gm; @@ -429,7 +433,7 @@ sub NormalizeItem { s/^(X-RADICALE-NAME)(;[^:;\n]*)*:.*\r?\n?//gm; } - if ($google || $yahoo) { + if ($googlecaldav || $yahoo) { # default status is CONFIRMED s/^STATUS:CONFIRMED\r?\n?//gm; } @@ -650,6 +654,11 @@ sub NormalizeItem { s/^DESCRIPTION:Reminder\n//m; } + if ($googleeas) { + # unsupported properties + s/^(FN)(;[^:;\n]*)*:.*\r?\n?//gm; + } + # treat X-MOZILLA-HTML=FALSE as if the property didn't exist s/^X-MOZILLA-HTML:FALSE\r?\n?//gm; -- 2.7.4