Imported Upstream version 1.5 upstream upstream/1.5
authorPatrick Ohly <patrick.ohly@intel.com>
Tue, 4 Nov 2014 14:48:59 +0000 (14:48 +0000)
committerPatrick Ohly <patrick.ohly@intel.com>
Tue, 4 Nov 2014 14:48:59 +0000 (14:48 +0000)
41 files changed:
ChangeLog
Makefile.in
NEWS
README
configure
configure.ac
src/backends/pbap/PbapSyncSource.cpp
src/backends/signon/signon.cpp
src/backends/signon/signonRegister.cpp
src/dbus/server/main.cpp
src/dbus/server/pim/examples/search.py
src/dbus/server/pim/examples/sync.py
src/dbus/server/pim/manager.cpp
src/dbus/server/pim/testpim.py
src/dbus/server/server.am
src/dbus/server/server.cpp
src/dbus/server/server.h
src/syncevo/GLibSupport.h
src/syncevo/GVariantSupport.cpp
src/syncevo/SyncContext.cpp
src/syncevo/configs/scripting/00looptimeout.xml [new file with mode: 0644]
src/syncevo/configs/scripting/05vcard-merge.xml
src/syncevo/configs/scripting/client/00timeout.xml [deleted file]
src/synthesis/ChangeLog
src/synthesis/configure
src/synthesis/configure.in
src/synthesis/src/sysync/multifielditem.cpp
src/synthesis/src/sysync/multifielditem.h
src/synthesis/src/sysync/multifielditemtype.cpp
src/testcases/eds_contact.vcf.filekde.tem [new file with mode: 0644]
test/ClientTest.cpp
test/client-test-main.cpp
test/synccompare.pl
test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/local-synced
test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/modify-local
test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/modify-remote
test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/remote-synced
test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/local-synced
test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/modify-local
test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/modify-remote
test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/remote-synced

index 39cd6de..d71035c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,191 @@
 # Generated by configure.  Do not edit.
 
+2014-10-31  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * NEWS:
+       * configure.ac:
+
+       autotools, NEWS: SyncEvolution 1.5
+
+2014-10-31  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/backends/signon/signon.cpp:
+       * src/syncevo/GVariantSupport.cpp:
+
+       signon: fix HashTable2Variant() ref counting (TC-1667)
+
+2014-10-30  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * configure.ac:
+
+       autotools: bump libsynthesis requirement
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/syncevo/SyncContext.cpp:
+
+       sync: ignore unnecessary username property
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/logger.py:
+       * test/wrappercheck.sh:
+
+       wrappercheck: augment output of daemon with time stamps
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/wrappercheck.sh:
+
+       wrappercheck: fix repeated daemon startup
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/wrappercheck.sh:
+
+       wrappercheck: augment output
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/wrappercheck.sh:
+
+       wrappercheck: configurable sleep after daemon launch
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/dbus/server/main.cpp:
+       * src/dbus/server/server.cpp:
+       * src/dbus/server/server.h:
+
+       D-Bus server: fix unreliable shutdown handling
+
+2014-10-24  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/syncevo/GLibSupport.h:
+
+       glib: add GIOChannelCXX
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/test-dbus.py:
+
+       testing: include stack backtrace when killing stuck process
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/sys.supp:
+
+       testing: ignore some minor leaks
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/local-synced:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/modify-local:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/modify-remote:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateLocalWins/remote-synced:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/local-synced:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/modify-local:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/modify-remote:
+       * test/testcases/synctests/googlecontacts/eds_contact/testUpdateRemoteWins/remote-synced:
+
+       testing: Google testcases must work with and without
+       libphonenumber support in EDS
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/synccompare.pl:
+
+       testing: ignore valid Akonadi vCard changes
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/testcases/eds_contact.vcf.filekde.tem.patch:
+
+       testing: ignore Akonadi encodig issues
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/runtests.py:
+
+       testing: ignore Akonadi
+       Client::Sync::file_event::testAddBothSides failures
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/ClientTest.cpp:
+       * test/runtests.py:
+
+       testing: ignore Memotoo eds_memo update failures
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/ClientTest.cpp:
+
+       testing: give valgrind more time in SyncTests::testTimeout()
+
+2014-10-10  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/dbus/server/pim/testpim.py:
+
+       PIM testing: allow testSync to run longer udner valgrind
+
+2014-09-25  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/syncevo/configs/scripting/00looptimeout.xml:
+       * src/syncevo/configs/scripting/client/00timeout.xml:
+
+       scripting: prevent premature loop timeouts
+
+2014-09-18  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * test/client-test-main.cpp:
+
+       testing: run one test per client-test instance
+
+2014-05-27  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/dbus/server/server.am:
+
+       PIM: always install examples
+
+2014-05-27  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/dbus/server/pim/examples/search.py:
+       * src/dbus/server/pim/examples/sync.py:
+
+       PIM: make examples work with recent Python GNOME
+
+2014-05-27  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/backends/signon/signonRegister.cpp:
+
+       signon: fix providersignon.so
+
+2014-10-09  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/dbus/server/pim/manager.cpp:
+
+       PIM testing: use file source similar to PBAP (part of FDO #84710)
+
+2014-10-09  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/syncevo/configs/scripting/05vcard-merge.xml:
+
+       vcard: fix caching of PBAP contacts (FDO #84710)
+
+2014-10-09  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/syncevo/configs/scripting/05vcard-merge.xml:
+
+       vcard: remove duplicate loops
+
+2014-09-22  Mateusz Polrola  <mateusz.polrola@gmail.com>
+
+       * src/backends/pbap/PbapSyncSource.cpp:
+
+       PBAP: Wrong behaviour when SYNCEVOLUTION_PBAP_CHUNK_TRANSFER_TIME
+       is <= 0.
+
 2014-09-10  Patrick Ohly  <patrick.ohly@intel.com>
 
        * NEWS:
index 303ad65..6f6d750 100644 (file)
@@ -171,7 +171,7 @@ DIST_COMMON = README $(am__configure_deps) \
        INSTALL NEWS compile config.guess config.sub depcomp \
        install-sh ltmain.sh missing mkinstalldirs
 test_PROGRAMS = $(am__EXEEXT_9)
-bin_PROGRAMS = $(am__EXEEXT_4) $(am__append_84) $(am__append_88)
+bin_PROGRAMS = $(am__EXEEXT_4) $(am__append_85) $(am__append_89)
 libexec_PROGRAMS = src/syncevo-local-sync$(EXEEXT) $(am__EXEEXT_5)
 noinst_PROGRAMS = $(am__EXEEXT_6) $(am__EXEEXT_7) $(am__EXEEXT_8)
 EXTRA_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
@@ -407,16 +407,21 @@ TESTS =
 @COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@am__append_79 = \
 @COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@  src/dbus/server/pim/org._01.pim.contacts.service.in
 
-@COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@@ENABLE_TESTING_TRUE@am__append_80 = \
+@COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@am__append_80 = \
+@COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@   src/dbus/server/pim/examples/search.py \
+@COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@   src/dbus/server/pim/examples/sync.py \
+@COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@   $(NOP)
+
+@COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@@ENABLE_TESTING_TRUE@am__append_81 = \
 @COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@@ENABLE_TESTING_TRUE@      src/dbus/server/pim/testpim.py \
 @COND_DBUS_PIM_TRUE@@COND_DBUS_TRUE@@ENABLE_TESTING_TRUE@      $(NOP)
 
-@COND_DBUS_TRUE@am__append_81 = \
+@COND_DBUS_TRUE@am__append_82 = \
 @COND_DBUS_TRUE@  $(src_dbus_server_service_files_in) \
 @COND_DBUS_TRUE@  $(src_dbus_server_script_in) \
 @COND_DBUS_TRUE@  $(src_dbus_server_desktop_in)
 
-@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_82 = src/gtk-ui/README \
+@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_83 = src/gtk-ui/README \
 @COND_GTK2_TRUE@@COND_GUI_TRUE@        $(src_gtk_ui_applications_in_files)
 
 # sync-ui: default GUI, could be plain GTK or Moblin UX
@@ -424,17 +429,17 @@ TESTS =
 # sync-ui-moblin: Moblin UX
 #
 # The later two are built when --enable-gui=all was used.
-@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_83 = \
+@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_84 = \
 @COND_GTK2_TRUE@@COND_GUI_TRUE@  src/gtk-ui/sync-ui \
 @COND_GTK2_TRUE@@COND_GUI_TRUE@  src/gtk-ui/sync-ui-gtk \
 @COND_GTK2_TRUE@@COND_GUI_TRUE@  src/gtk-ui/sync-ui-moblin
 
-@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_84 = @GUI_PROGRAMS@
-@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_85 = \
+@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_85 = @GUI_PROGRAMS@
+@COND_GTK2_TRUE@@COND_GUI_TRUE@am__append_86 = \
 @COND_GTK2_TRUE@@COND_GUI_TRUE@  src/gtk-ui/sync-moblin.desktop \
 @COND_GTK2_TRUE@@COND_GUI_TRUE@  $(src_gtk_ui_applications_generated)
 
-@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_86 = src/gtk3-ui/README \
+@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_87 = src/gtk3-ui/README \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@       $(src_gtk3_ui_applications_in_files)
 
 # sync-ui: default GUI, could be plain GTK or Moblin UX
@@ -442,20 +447,20 @@ TESTS =
 # sync-ui-moblin: Moblin UX
 #
 # The later two are built when --enable-gui=all was used.
-@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_87 = \
+@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_88 = \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@  src/gtk3-ui/sync-ui \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@  src/gtk3-ui/sync-ui-gtk \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@  src/gtk3-ui/sync-ui-moblin
 
-@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_88 = @GUI_PROGRAMS@
-@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_89 = \
+@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_89 = @GUI_PROGRAMS@
+@COND_GTK2_FALSE@@COND_GUI_TRUE@am__append_90 = \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@  src/gtk3-ui/sync-moblin.desktop \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@  $(src_gtk3_ui_applications_generated)
 
-@COND_DBUS_TRUE@am__append_90 = src/syncevo-http-server
+@COND_DBUS_TRUE@am__append_91 = src/syncevo-http-server
 # SYNCEVOLUTION_LDADD is defined in configure script.
-@ENABLE_MODULES_FALSE@am__append_91 = @SYNCSOURCES@
 @ENABLE_MODULES_FALSE@am__append_92 = @SYNCSOURCES@
+@ENABLE_MODULES_FALSE@am__append_93 = @SYNCSOURCES@
 
 # The files which register backends have to be compiled into
 # "client-test" and "syncevolution" in order to pull in the
@@ -466,36 +471,36 @@ TESTS =
 # When using modules the registration is done inside the
 # module and the register file is unnecessary. However, they
 # still need to be included in "make dist".
-@ENABLE_MODULES_TRUE@am__append_93 = $(BACKEND_REGISTRIES)
-@ENABLE_MODULES_FALSE@am__append_94 = $(BACKEND_REGISTRIES)
+@ENABLE_MODULES_TRUE@am__append_94 = $(BACKEND_REGISTRIES)
+@ENABLE_MODULES_FALSE@am__append_95 = $(BACKEND_REGISTRIES)
 
 # Force inclusion of our own icaltz-util.o into binaries even though
 # we do not call the icaltzutil_fetch_timezone directly ourself.
 # That way it is there if or when libical needs it.
-@ENABLE_ICALTZ_UTIL_TRUE@am__append_95 = -Wl,-usyncevo_fetch_timezone
-@COND_DBUS_TRUE@am__append_96 = $(gdbus_build_dir)/libgdbussyncevo.la
+@ENABLE_ICALTZ_UTIL_TRUE@am__append_96 = -Wl,-usyncevo_fetch_timezone
 @COND_DBUS_TRUE@am__append_97 = $(gdbus_build_dir)/libgdbussyncevo.la
+@COND_DBUS_TRUE@am__append_98 = $(gdbus_build_dir)/libgdbussyncevo.la
 
 # Do the linking here, as with all SyncEvolution executables.
 # Sources are compiled in dbus/server.
 # DBus Server
 
 # syncevo-dbus-server's helper binary
-@COND_DBUS_TRUE@am__append_98 = src/syncevo-dbus-server \
+@COND_DBUS_TRUE@am__append_99 = src/syncevo-dbus-server \
 @COND_DBUS_TRUE@       src/syncevo-dbus-helper
-@COND_DBUS_TRUE@am__append_99 = src/dbus/server/libsyncevodbushelper.la src/dbus/server/libsyncevodbusserver.la
-@ENABLE_EVOLUTION_COMPATIBILITY_FALSE@am__append_100 = $(LIBICAL_LIBS)
+@COND_DBUS_TRUE@am__append_100 = src/dbus/server/libsyncevodbushelper.la src/dbus/server/libsyncevodbusserver.la
+@ENABLE_EVOLUTION_COMPATIBILITY_FALSE@am__append_101 = $(LIBICAL_LIBS)
 
 # distribute test system?
 # yes: install client-test and test files in testdir
-@ENABLE_TESTING_TRUE@am__append_101 = src/client-test
+@ENABLE_TESTING_TRUE@am__append_102 = src/client-test
 # The "all" dependency causes a rebuild even if the actual input files
 # haven't changed. If client-test is part of the regular targets built
 # by "all", then it must not depend on all!
-@ENABLE_TESTING_FALSE@am__append_102 = src/client-test
-@ENABLE_TESTING_FALSE@am__append_103 = $(CLIENT_LIB_TEST_FILES)
-@ENABLE_TESTING_FALSE@am__append_104 = all
-@COND_CORE_TRUE@am__append_105 = test/abort-redirect.cpp \
+@ENABLE_TESTING_FALSE@am__append_103 = src/client-test
+@ENABLE_TESTING_FALSE@am__append_104 = $(CLIENT_LIB_TEST_FILES)
+@ENABLE_TESTING_FALSE@am__append_105 = all
+@COND_CORE_TRUE@am__append_106 = test/abort-redirect.cpp \
 @COND_CORE_TRUE@       test/ClientTest.h test/ClientTestAssert.h \
 @COND_CORE_TRUE@       test/ClientTest.cpp test/client-test-main.cpp \
 @COND_CORE_TRUE@       test/test.h test/test.cpp $(test_testcases) \
@@ -505,9 +510,9 @@ TESTS =
 @COND_CORE_TRUE@       $(wildcard test/testcases/*.patch)
 
 # generic D-Bus client/server tests
-@COND_CORE_TRUE@@COND_DBUS_TRUE@am__append_106 = test/dbus-client-server
-@COND_CORE_TRUE@@COND_DBUS_TRUE@@ENABLE_UNIT_TESTS_TRUE@am__append_107 = test/test.cpp
-@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_108 = \
+@COND_CORE_TRUE@@COND_DBUS_TRUE@am__append_107 = test/dbus-client-server
+@COND_CORE_TRUE@@COND_DBUS_TRUE@@ENABLE_UNIT_TESTS_TRUE@am__append_108 = test/test.cpp
+@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_109 = \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/__init__.py \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/test-dbus.py \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/testdbus.py \
@@ -518,13 +523,13 @@ TESTS =
 # uses the right SyncEvolution without depending on the PATH.
 # client-test should have been installed in testdir already as
 # normal executable, see src.am.
-@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_109 = install-test-files
-@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_110 = uninstall-test-files
-@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_111 = \
+@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_110 = install-test-files
+@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_111 = uninstall-test-files
+@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_112 = \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/Makefile \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  $(NOP)
 
-@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_112 = \
+@COND_CORE_TRUE@@ENABLE_TESTING_TRUE@am__append_113 = \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  $(test_testcases) \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/test-dbus/templates/templates/clients/phone/nokia/S40/7210c.ini \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/test-dbus/templates/templates/clients/SyncEvolution.ini \
@@ -571,14 +576,14 @@ TESTS =
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  test/test-dbus/reports/cache/syncevolution/dummy__test-2009-11-18-12-56/status.ini \
 @COND_CORE_TRUE@@ENABLE_TESTING_TRUE@  $(NOP)
 
-@COND_CORE_TRUE@am__append_113 = po
-@COND_CORE_TRUE@am__append_114 = README NEWS COPYING $(TEST_README_FILES) test/syncevo-http-server-logging.conf
-@COND_CORE_TRUE@am__append_115 = $(disted_docs)
+@COND_CORE_TRUE@am__append_114 = po
+@COND_CORE_TRUE@am__append_115 = README NEWS COPYING $(TEST_README_FILES) test/syncevo-http-server-logging.conf
 @COND_CORE_TRUE@am__append_116 = $(disted_docs)
-@COND_CORE_TRUE@@COND_HTML_README_TRUE@am__append_117 = README.html
-# do not distribute in tarball.
+@COND_CORE_TRUE@am__append_117 = $(disted_docs)
 @COND_CORE_TRUE@@COND_HTML_README_TRUE@am__append_118 = README.html
-@COND_CORE_TRUE@@COND_MAN_PAGES_TRUE@am__append_119 = syncevolution.1
+# do not distribute in tarball.
+@COND_CORE_TRUE@@COND_HTML_README_TRUE@am__append_119 = README.html
+@COND_CORE_TRUE@@COND_MAN_PAGES_TRUE@am__append_120 = syncevolution.1
 
 # check .so (relevant for modular builds) and main syncevolution binary
 # (relevant in that case and for static builds) for dependencies on
@@ -587,13 +592,13 @@ TESTS =
 # Exclude *-[0-9].so, these are EXTRA_BACKENDS for which other rules apply.
 #
 # ical_strdup is an exception because it is in SyncEvolution.
-@ENABLE_EVOLUTION_COMPATIBILITY_TRUE@am__append_120 = toplevel_so_check
+@ENABLE_EVOLUTION_COMPATIBILITY_TRUE@am__append_121 = toplevel_so_check
 # libneon is intentionally not linked against, to choose between
 # GNUTLS and OpenSSL at runtime.
 # Allow undefined references to libstdcxx. This happens when
 # adding backends compiled on more recent Linux distros into
 # the release archive.
-@NEON_COMPATIBILITY_TRUE@am__append_121 = -e 'symbol ne_.*syncdav.so' \
+@NEON_COMPATIBILITY_TRUE@am__append_122 = -e 'symbol ne_.*syncdav.so' \
 @NEON_COMPATIBILITY_TRUE@      -e '@GLIBCXX_[^ ]* used by'
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -2578,7 +2583,7 @@ STABLE_VERSION = @STABLE_VERSION@
 STRIP = @STRIP@
 SYNCEVOLUTION_CFLAGS = @SYNCEVOLUTION_CFLAGS@
 SYNCEVOLUTION_CXXFLAGS = @SYNCEVOLUTION_CXXFLAGS@
-SYNCEVOLUTION_LDADD = @SYNCEVOLUTION_LDADD@ $(am__append_91)
+SYNCEVOLUTION_LDADD = @SYNCEVOLUTION_LDADD@ $(am__append_92)
 SYNCEVOLUTION_LIBS = @SYNCEVOLUTION_LIBS@
 SYNCEVOLUTION_LOCALEDIR = @SYNCEVOLUTION_LOCALEDIR@
 SYNCEVO_DBUS_SERVER_ARGS = @SYNCEVO_DBUS_SERVER_ARGS@
@@ -2670,8 +2675,8 @@ top_srcdir = @top_srcdir@
 # clean variables
 CLEANFILES = $(am__append_28) $(src_dbus_interfaces_built_sources) \
        src/dbus/interfaces/.stamp $(NONE) $(am__append_59) \
-       $(am__append_64) $(am__append_77) $(am__append_85) \
-       $(am__append_89) src/libstdc++.a src/client-test \
+       $(am__append_64) $(am__append_77) $(am__append_86) \
+       $(am__append_90) src/libstdc++.a src/client-test \
        $(CLIENT_LIB_TEST_FILES) src/syncevo-http-server \
        src/syncevo-phone-config src/synclog2html \
        src/ClientTest.cpp.html src/abort-redirect.log \
@@ -2691,13 +2696,13 @@ pkgconfig_DATA = $(am__append_26) $(am__append_56) $(am__append_67)
 testparentdir = $(libdir)/syncevolution
 # Must end in "/test" so that we can use nobase_testparent_DATA=test/...
 testdir = $(testparentdir)/test
-test_DATA = $(am__append_111)
+test_DATA = $(am__append_112)
 nobase_test_DATA = 
-test_SCRIPTS = $(am__append_80) $(am__append_108)
-nobase_testparent_DATA = $(am__append_112)
+test_SCRIPTS = $(am__append_80) $(am__append_81) $(am__append_109)
+nobase_testparent_DATA = $(am__append_113)
 
 # standard variables with standard prefixes
-dist_doc_DATA = $(am__append_116)
+dist_doc_DATA = $(am__append_117)
 dist_noinst_DATA = $(am__append_8) $(am__append_13) \
        src/dbus/interfaces/spec-strip-docs.xsl \
        src/dbus/interfaces/spec-to-docbook.xsl \
@@ -2705,13 +2710,13 @@ dist_noinst_DATA = $(am__append_8) $(am__append_13) \
        src/dbus/interfaces/syncevo-server-full.xml \
        src/dbus/interfaces/syncevo-session-full.xml \
        src/dbus/interfaces/README $(am__append_55) $(am__append_66) \
-       $(am__append_81) $(am__append_82) $(am__append_86) \
+       $(am__append_82) $(am__append_83) $(am__append_87) \
        src/shlibs.local src/synthesis-includes/Makefile.am \
-       src/synthesis-includes/Makefile.in $(am__append_93) \
-       $(am__append_105) HACKING LICENSE.txt LICENSE.LGPL-21 \
+       src/synthesis-includes/Makefile.in $(am__append_94) \
+       $(am__append_106) HACKING LICENSE.txt LICENSE.LGPL-21 \
        README.rst description autogen.sh Doxyfile po/LINGUAS.README
 dist_pkgdata_DATA = $(am__append_69)
-doc_DATA = $(am__append_52) $(am__append_118)
+doc_DATA = $(am__append_52) $(am__append_119)
 
 # generate syntax-highlighted version of ClientTest.cpp for HTML
 # version of .log test results
@@ -2726,7 +2731,7 @@ bin_SCRIPTS = $(am__append_47) src/synclog2html
 dist_noinst_SCRIPTS = build/gen-git-version.sh build/source2html.py \
        $(am__append_32)
 libexec_SCRIPTS = $(am__append_78)
-nodist_bin_SCRIPTS = $(am__append_90) src/syncevo-phone-config
+nodist_bin_SCRIPTS = $(am__append_91) src/syncevo-phone-config
 
 # other
 
@@ -2739,8 +2744,8 @@ nodist_bin_SCRIPTS = $(am__append_90) src/syncevo-phone-config
 # found in a parent directory. However, these files are needed
 # later on during the recursive libsynthesis configure+make.
 all_dist_hooks = src_dist_hook dot_dist_hook
-all_install_exec_hooks = $(am__append_109)
-all_uninstall_hooks = $(am__append_110)
+all_install_exec_hooks = $(am__append_110)
+all_uninstall_hooks = $(am__append_111)
 
 # Check that no executable or shared object depends on symbols in
 # libraries that it does not link against. Unnecessarily linking
@@ -2748,7 +2753,7 @@ all_uninstall_hooks = $(am__append_110)
 # -Wl,--as-needed. Depends on dpkg-shlibdeps, skipped if that is
 # not available.
 all_local_installchecks = $(am__append_33) $(am__append_48) \
-       $(am__append_120) toplevel_link_check
+       $(am__append_121) toplevel_link_check
 
 # These dependencies are intentionally a bit too broad:
 # they ensure that all files are in place to *run* client-test.
@@ -2808,7 +2813,7 @@ EXTRA_DIST = build/export-foreign-git.sh build/export-gdbus.sh \
        src/dbus/server/pim/test-dbus/simple-sort/config/syncevolution/pim-manager.ini \
        src/dbus/server/pim/test-dbus/first-last-sort/config/syncevolution/pim-manager.ini \
        $(am__append_76) src/gtk-ui/ui.xml src/gtk3-ui/ui.xml
-SUBDIRS = $(am__append_1) $(am__append_2) . $(am__append_113)
+SUBDIRS = $(am__append_1) $(am__append_2) . $(am__append_114)
 AUTOMAKE_OPTIONS = subdir-objects
 ACLOCAL_AMFLAGS = -I m4 -I m4-repo ${ACLOCAL_FLAGS}
 @COND_GIO_GDBUS_FALSE@gdbus_dir = $(top_srcdir)/src/gdbus
@@ -2817,9 +2822,9 @@ ACLOCAL_AMFLAGS = -I m4 -I m4-repo ${ACLOCAL_FLAGS}
 @COND_GIO_GDBUS_TRUE@gdbus_dir = $(top_srcdir)/src/gdbusxx
 @COND_GIO_GDBUS_FALSE@gdbus_build_dir = src/gdbus
 @COND_GIO_GDBUS_TRUE@gdbus_build_dir = src/gdbusxx
-disted_docs = $(am__append_114)
-distbin_docs = $(am__append_115) $(am__append_117)
-man_MANS = $(am__append_119)
+disted_docs = $(am__append_115)
+distbin_docs = $(am__append_116) $(am__append_118)
+man_MANS = $(am__append_120)
 src_cppflags = -I$(top_srcdir)/src $(am__append_3) $(am__append_7) \
        $(am__append_12) $(am__append_34) $(am__append_51) \
        -I$(top_srcdir)/src/dbus -I$(top_srcdir)/test -I$(top_srcdir) \
@@ -3705,14 +3710,14 @@ src_cppflags = -I$(top_srcdir)/src $(am__append_3) $(am__append_7) \
 @COND_GTK2_FALSE@@COND_GUI_TRUE@src_gtk3_ui_sync_ui_moblin_LDADD = $(src_gtk3_ui_sync_ui_LDADD)
 @COND_GTK2_FALSE@@COND_GUI_TRUE@src_gtk3_ui_sync_ui_moblin_CFLAGS = $(src_gtk3_ui_sync_ui_CFLAGS)
 @COND_GTK2_FALSE@@COND_GUI_TRUE@src_gtk3_ui_sync_ui_moblin_CPPFLAGS = $(src_gtk3_ui_sync_ui_CPPFLAGS) -DUSE_MOBLIN_UX
-SYNCEVOLUTION_DEP = $(am__append_92)
-CORE_SOURCES = $(am__append_94)
+SYNCEVOLUTION_DEP = $(am__append_93)
+CORE_SOURCES = $(am__append_95)
 CORE_CXXFLAGS = $(SYNTHESIS_CFLAGS) $(CPPUNIT_CXXFLAGS)
 CORE_LDADD = $(SYNCEVOLUTION_LDADD) src/syncevo/libsyncevolution.la $(GLIB_LIBS) $(GTHREAD_LIBS) $(GOBJECT_LIBS) $(LIBS)
 CORE_DEP = $(SYNCEVOLUTION_DEP) src/syncevo/libsyncevolution.la $(SYNTHESIS_DEP)
 CORE_LD_FLAGS = -Wl,-uSyncEvolution_Module_Version \
        -Wl,--export-dynamic $(CPPUNIT_LDFLAGS) $(ADDITIONAL_LDFLAGS) \
-       $(am__append_95)
+       $(am__append_96)
 src_syncevolution_SOURCES = \
   src/syncevolution.cpp \
   $(CORE_SOURCES)
@@ -3722,9 +3727,9 @@ src_syncevolution_SOURCES = \
 # SYNCEVOLUTION_LDADD will be replaced with libsyncebook.la/libsyncecal.la/libsyncsqlite.la
 # if linking statically against them, empty otherwise;
 # either way this does not lead to a dependency on those libs - done explicitly
-src_syncevolution_LDADD = $(CORE_LDADD) $(am__append_96)
+src_syncevolution_LDADD = $(CORE_LDADD) $(am__append_97)
 src_syncevolution_DEPENDENCIES = $(EXTRA_LTLIBRARIES) $(CORE_DEP) \
-       $(am__append_97)
+       $(am__append_98)
 src_syncevolution_LDFLAGS = $(PCRECPP_LIBS) $(CORE_LD_FLAGS) $(DBUS_LIBS)
 src_syncevolution_CXXFLAGS = $(PCRECPP_CFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(CORE_CXXFLAGS) $(DBUS_CFLAGS) $(SYNCEVO_WFLAGS)
 src_syncevolution_CPPFLAGS = $(src_cppflags) -I$(gdbus_dir)
@@ -3770,7 +3775,7 @@ src_client_test_SOURCES = \
   test/client-test-main.cpp \
   $(CORE_SOURCES)
 
-nodist_src_client_test_SOURCES = test/test.cpp $(am__append_103)
+nodist_src_client_test_SOURCES = test/test.cpp $(am__append_104)
 
 # List of test files which get copied verbatim from
 # $(top_srcdir)/test/testcases/ to src/testcases below. test/test.am
@@ -3800,7 +3805,7 @@ TEST_FILES_PATCHED = $(wildcard src/testcases/*.tem)
 # To pull in those object files, LDFLAGS must contain undef statements
 # for the C symbols exported by the macro.
 src_client_test_libs = src/syncevo/libsyncevolution.la \
-       $(am__append_99)
+       $(am__append_100)
 
 # src/syncevo/libsyncevolution.la -> src/syncevo/.libs/libsyncevolution.a -> -Wl,-u...
 src_client_test_undef = $(shell nm $(patsubst %.la,%.a,$(subst /lib,/.libs/lib,$(src_client_test_libs))) | grep funambolAutoRegisterRegistry | sed -e 's/.* /-Wl,-u/' )
@@ -3809,7 +3814,7 @@ src_client_test_CXXFLAGS = $(filter-out -O2, @CPPUNIT_CXXFLAGS@ $(PCRECPP_CFLAGS
 src_client_test_LDFLAGS = @CPPUNIT_LDFLAGS@  $(src_client_test_undef) $(CORE_LD_FLAGS) $(QT_LDFLAGS)
 src_client_test_LDADD = $(src_client_test_libs) $(CORE_LDADD) \
        $(PCRECPP_LIBS) $(SYNTHESIS_ENGINE) $(QT_LIBS) \
-       $(am__append_100)
+       $(am__append_101)
 
 # The binary does not really depend on the test cases, only running it does.
 # Listing the dependencies here is done to ensure that one doesn't accidentally
@@ -3817,7 +3822,7 @@ src_client_test_LDADD = $(src_client_test_libs) $(CORE_LDADD) \
 src_client_test_DEPENDENCIES = $(EXTRA_LTLIBRARIES) \
        $(src_client_test_libs) $(CORE_DEP) $(CLIENT_LIB_TEST_FILES) \
        testcase2patch src/synccompare src/synclog2html src/templates \
-       $(am__append_104)
+       $(am__append_105)
 @ENABLE_TESTING_TRUE@src_testcasesdir = $(testdir)/testcases
 @ENABLE_TESTING_TRUE@dist_src_testcases_DATA = $(TEST_FILES_GENERATED)
 @ENABLE_TESTING_TRUE@src_testcases_lcsdir = $(testdir)/testcases/lcs
@@ -3884,7 +3889,7 @@ src_abort_redirect_DEPENDENCIES = all
 
 @COND_CORE_TRUE@@COND_DBUS_TRUE@test_dbus_client_server_SOURCES =  \
 @COND_CORE_TRUE@@COND_DBUS_TRUE@       test/dbus-client-server.cpp \
-@COND_CORE_TRUE@@COND_DBUS_TRUE@       $(am__append_107)
+@COND_CORE_TRUE@@COND_DBUS_TRUE@       $(am__append_108)
 @COND_CORE_TRUE@@COND_DBUS_TRUE@test_dbus_client_server_CPPFLAGS = -I$(gdbus_dir) -I$(top_srcdir)/src
 @COND_CORE_TRUE@@COND_DBUS_TRUE@test_dbus_client_server_CXXFLAGS = $(CPPUNIT_CXXFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(BACKEND_CPPFLAGS) $(DBUS_CFLAGS) $(GLIB_CFLAGS) $(GOBJECT_CFLAGS) $(PCRECPP_CFLAGS)
 @COND_CORE_TRUE@@COND_DBUS_TRUE@test_dbus_client_server_LDFLAGS = $(CPPUNIT_LDFLAGS)
@@ -3965,7 +3970,7 @@ SYNCEVOLUTION_evolution_DEB_REQUIRES = \
 # Some exceptions for the link check above (= symbol may be used without linking).
 # SySync_ConsolePrintf is expected by libsmltk and has to be provided by caller.
 LINK_CHECK_ALLOWED = -e xxxxxxxx -e \
-       'SySync_ConsolePrintf.*libsmltk.so' $(am__append_121)
+       'SySync_ConsolePrintf.*libsmltk.so' $(am__append_122)
 @COND_CROSS_COMPILING_FALSE@RUN_SYNCEVOLUTION_CHECK = die if $$?; return $$buffer;
 
 # Be strict about running 'syncevolution' only when not doing
diff --git a/NEWS b/NEWS
index 169fb6e..7759ace 100644 (file)
--- a/NEWS
+++ b/NEWS
+SyncEvolution 1.4.1 -> 1.5, 31.10.2014
+======================================
+
+Based on community feedback and discussions, the terminology used in
+SyncEvolution for configuration, local sync and database access was
+revised. Some usability issues with setting up access to databases
+were addressed.
+
+Interoperability with WebDAV servers and in particular Google Contacts
+was enhanced considerably. Access to iCloud contacts was reported as
+working when using username=foobar@icloud.com and password, but is not
+formally tested. Syncing with iCloud calendars ran into a server
+limitation (reported as 17001498 "CalDAV REPORT drops calendar data")
+and needs further work (FDO #72133).
+
+Contact data gets converted to and from the format typically used by
+CardDAV servers, so now anniversary, spouse, manager, assistant and
+instant message information are exchanged properly. Custom labels get
+stored in EDS as extensions and no longer get lost when updating some
+other aspects of a contact. However, Evolution does not show custom
+labels and removes them when editing a property which has a custom
+label (BGO #730636).
+
+Scanning for CardDAV/CalDAV resources was enhanced. It now finds
+additional calendars with Google CalDAV.  For Google, the obsolete
+SyncML config template was removed and CalDAV/CardDAV were merged into
+a single "Google" template.
+
+Using Google Calendar/Contacts with OAuth2 authentication on a
+headless server becomes a bit easier: it is possible to set up access
+on one system with a GUI using either gSSO or GNOME Online Accounts,
+then take the OAuth2 refresh token and use it in SyncEvolution on a
+different system. See
+http://cgit.freedesktop.org/SyncEvolution/syncevolution/tree/src/backends/oauth2/README
+
+The PIM Manager API also supports Google Contact syncing. Some
+problems with suspending a PBAP sync were fixed. Suspend/abort can
+be tested with the sync.py example.
+
+Performance is better for local syncs and PBAP caching. The most
+common case, a two-way sync with no changes on either side, no longer
+rewrites any meta data files. CPU consumption during local sync was
+reduced to one third by exchanging messages via shared memory instead
+of internal D-Bus. Redundant vCard decode/encode on the sending side
+of PBAP and too agressive flushing of meta data during a normal sync
+were removed.
+
+The EDS memo backend is able to switch between syncing in plain
+text and iCalendar 2.0 VJOURNAL automatically.
+
+
+Details:
+
+* source -> datastore rename, improved terminology
+
+  The word "source" implies reading, while in fact access is read/write.
+  "datastore" avoids that misconception. Writing it in one word emphasizes
+  that it is single entity.
+
+  While renaming, also remove references to explicit --*-property
+  parameters. The only necessary use today is "--sync-property ?"
+  and "--datastore-property ?".
+
+  --datastore-property was used instead of the short --store-property
+  because "store" might be mistaken for the verb. It doesn't matter
+  that it is longer because it doesn't get typed often.
+
+  --source-property must remain valid for backward compatility.
+
+  As many user-visible instances of "source" as possible got replaced in
+  text strings by the newer term "datastore". Debug messages were left
+  unchanged unless some regex happened to match it.
+
+  The source code will continue to use the old variable and class names
+  based on "source".
+
+  Various documentation enhancements:
+    Better explain what local sync is and how it involves two sync
+    configs. "originating config" gets introduces instead of just
+    "sync config".
+
+    Better explain the relationship between contexts, sync configs,
+    and source configs ("a sync config can use the datastore configs in
+    the same context").
+
+    An entire section on config properties in the terminology
+    section. "item" added (Todd Wilson correctly pointed out that it was
+    missing).
+
+    Less focus on conflict resolution, as suggested by Graham Cobb.
+
+    Fix examples that became invalid when fixing the password
+    storage/lookup mechanism for GNOME keyring in 1.4.
+
+    The "command line conventions", "Synchronization beyond SyncML" and
+    "CalDAV and CardDAV" sections were updated. It's possible that the
+    other sections also contain slightly incorrect usage of the
+    terminology or are simply out-dated.
+
+* local sync: allow config name in syncURL=local://
+
+  Previously, only syncURL=local://@<context name> was allowed and used
+  the "target-config@context name" config as target side in the local
+  sync.
+
+  Now "local://config-name@context-name" or simply "local://config-name"
+  are also allowed. "target-config" is still the fallback if only a
+  context is give.
+
+  It also has one more special meaning: "--configure
+  target-config@google" will pick the "Google" template automatically
+  because it knows that the intention is to configure the target side
+  of a local sync. It does not know that when using some other name
+  for the config, in which case the template (if needed) must be
+  specified explicitly.
+
+  The process name in output from the target side now also includes the
+  configuration name if it is not the default "target-config".
+
+* command line: revise usability checking of datastores
+
+  When configuring a new sync config, the command line checks whether a
+  datastore is usable before enabling it. If no datastores were listed
+  explicitly, only the usable ones get enabled. If unusable datastores
+  were explicitly listed, the entire configure operation fails.
+
+  This check was based on listing databases, which turned out to be too
+  unspecific for the WebDAV backend: when "database" was set to some URL
+  which is good enough to list databases, but not a database URL itself,
+  the sources where configured with that bad URL.
+
+  Now a new SyncSource::isUsable() operation is used, which by default
+  just falls back to calling the existing Operations::m_isEmpty. In
+  practice, all sources either check their config in open() or the
+  m_isEmpty operation, so the source is usable if no error is
+  enountered.
+
+  For WebDAV, the usability check is skipped because it would require
+  contacting a remote server, which is both confusing (why does a local
+  configure operation need the server?) and could fail even for valid
+  configs (server temporarily down). The check was incomplete anyway
+  because listing databases gave a fixed help text response when no
+  credentials were given. For usability checking that should have
+  resulted in "not usable" and didn't.
+
+  The output during the check was confusing: it always said "listing
+  databases" without giving a reason why that was done. The intention
+  was to give some feedback while a potentially expensive operation
+  ran. Now the isUsable() method itself prints "checking usability" if
+  (and only if!) such a check is really done.
+
+  Sometimes datastores were checked even when they were about to be
+  configure as "disabled" already. Now checking such datastores is
+  skipped.
+
+* command line: fix --update from directory
+
+  The "--update <dir name>" operation was supposed to take the
+  item luids from the file names inside the directory. That part
+  had not been implemented, turning the operation accidentally
+  into an "--import".
+
+  Also missing was the escaping/unescaping of luids. Now the
+  same escaping is done as in command line output and command
+  line parsing to make the luids safe for use as file name.
+
+* sync output: hide "<source>: started" INFO messages
+
+  These messages get printed at the start of processing each
+  SyncML message. This is not particularly useful and just
+  adds noise to the output.
+
+* config: allow storing credentials for email address
+
+  When configuring a WebDAV server with username = email address and no
+  URL (which is possible if the server supports service discovery via
+  the domain in the email address), then storing the credentials in the
+  GNOME keyring used to fail with "cannot store password in GNOME
+  keyring, not enough attributes".
+
+  That is because GNOME keyring seemed to get confused when a network
+  login has no server name and some extra safeguards were added to
+  SyncEvolution to avoid this.
+
+  To store the credentials in the case above, the email address now gets
+  split into user and domain part and together get used to look up the
+  password.
+
+* config: ignore unnecessary username property
+
+  A local sync or Bluetooth sync do not need the 'username' property.
+  When it is set despite that, issue a warning.
+
+  Previously, the value was checked even when not needed, which
+  caused such syncs to fail when set to something other than a plain
+  username.
+
+* config templates: Funambol URLs
+
+  Funambol turned of the URL redirect from my.funambol.com to
+  onemedia.com. The Funambol template now uses the current URL.  Users
+  with existing Funambol configs must updated the syncURL property
+  manually to https://onemediahub.com/sync
+
+  Kudos to Daniel Clement for reporting the change.
+
+* EDS: memo syncing as iCalendar 2.0 (FDO #52714)
+
+  When syncing memos with a peer which also supports iCalendar 2.0 as
+  data format, the engine will now pick iCalendar 2.0 instead of
+  converting to/from plain text. The advantage is that some additional
+  properties like start date and categories can also be synchronized.
+
+  The code is a lot simpler, too, because the EDS specific iCalendar 2.0
+  <-> text conversion code can be removed.
+
+* SoupTransport: drop CA file check
+
+  It used to be necessary to specify a CA file for libsoup to enable SSL
+  certificate checking. Nowadays libsoup uses the default CA store
+  unless told otherwise, so the check in SyncEvolution became
+  obsolete. However, now there is a certain risk that no SSL checking is
+  done although the user asked for it (when libsoup is not recent enough
+  or compiled correctly).
+
+* CardDAV: use Apple/Google/CardDAV vCard flavor
+
+  In principle, CardDAV servers support arbitrary vCard 3.0
+  data. Extensions can be different and need to be preserved. However,
+  when multiple different clients or the server's Web UI interpret the
+  vCards, they need to agree on the semantic of these vCard extensions.
+
+  In practice, CardDAV was pushed by Apple and Apple clients are
+  probably the most common clients of CardDAV services. When the Google
+  Contacts Web UI creates or edits a contact, Google CardDAV will
+  send that data using the vCard flavor used by Apple.
+
+  Therefore it makes sense to exchange contacts with *all* CardDAV
+  servers using that format. This format could be made configurable in
+  SyncEvolution on a case-by-case basis; at the moment, it is
+  hard-coded.
+
+  During syncing, SyncEvolution takes care to translate between the
+  vCard flavor used internally (based on Evolution) and the CardDAV
+  vCard flavor. This mapping includes:
+
+  X-AIM/JABBER/... <-> IMPP + X-SERVICE-TYPE
+
+    Any IMPP property declared as X-SERVICE-TYPE=AIM will get
+    mapped to X-AIM. Same for others. Some IMPP service types
+    have no known X- property extension; they are stored in
+    EDS as IMPP. X- property extensions without a known X-SERVICE-TYPE
+    (for example, GaduGadu and Groupwise) are stored with
+    X-SERVICE-TYPE values chosen by SyncEvolution so that
+    Google CardDAV preserves them (GroupWise with mixed case
+    got translated by Google into Groupwise, so the latter is used).
+
+    Google always sends an X-ABLabel:Other for IMPP. This is ignored
+    because the service type overrides it.
+
+    The value itself also gets transformed during the mapping. IMPP uses
+    an URI as value, with a chat protocol (like "aim" or "xmpp") and
+    some protocol specific identifier. For each X- extension the
+    protocol is determined by the property name and the value is the
+    protocol specific identifier without URL encoding.
+
+  X-SPOUSE/MANAGER/ASSISTANT <-> X-ABRELATEDNAMES + X-ABLabel
+
+    The mapping is based on the X-ABLabel property attached to
+    the X-ABRELATEDNAMES property. This depends on the English
+    words "Spouse", "Manager", "Assistant" that Google CardDAV
+    and Apple devices seem to use regardless of the configured
+    language.
+
+    As with IMPP, only the subset of related names which have
+    a corresponding X- property extension get mapped. The rest
+    is stored in EDS using the X-ABRELATEDNAMES property.
+
+  X-ANNIVERSARY <-> X-ABDATE
+
+    Same here, with X-ABLabel:Anniversary as the special case
+    which gets mapped.
+
+  X-ABLabel parameter <-> property
+
+    CardDAV vCards have labels attached to arbitrary other properties
+    (TEL, ADR, X-ABDATE, X-ABRELATEDNAMES, ...) via vCard group tags:
+    item1.X-ABDATE:2010-01-01
+    item1.X-ABLabel:Anniversary
+
+    The advantage is that property values can contain arbitrary
+    characters, including line breaks and double quotation marks,
+    which is not possible in property parameters.
+
+    Neither EDS nor KDE (judging from the lack of responses on the
+    KDE-PIM mailing list) support custom labels. SyncEvolution could
+    have used grouping as it is done in CardDAV, but grouping is not
+    used much (not at all?) by the UIs working with the vCards in EDS
+    and KDE. It seemed easier to use a new X-ABLabel parameter.
+
+    Characters which cannot be stored in a parameter get converted
+    (double space to single space, line break to space, etc.) during
+    syncing. In practice, these characters don't appear in X-ABLabel
+    properties anyway because neither Apple nor Google UIs allow entering
+    them for custom labels.
+
+    The "Other" label is used by Google even in case where it adds no
+    information. For example, all XMPP properties have an associated
+    X-ABLabel=Other although the Web UI does not provide a means to edit
+    or show such a label. Editing the text before the value in the UI
+    changes the X-SERVICE-TYPE parameter value, not the X-ABLabel as for
+    other fields.
+
+    Therefore the "Other" label is ignored by removing it during syncing.
+
+  X-EVOLUTION-UI-SLOT (the parameter used in Evolution to determine the
+  order of properties in the UI) gets stored in CardDAV. The only exception
+  is Google CardDAV which got confused when an IMPP property had both
+  X-SERVICE-TYPE and X-EVOLUTION-UI-SLOT parameters set. For Google,
+  X-EVOLUTION-UI-SLOT is only sent on other properties and thus ordering
+  of chat information can get lost when syncing with Google.
+
+* synccompare: support grouping and quoted parameter strings
+
+  Grouped properties are sorted first according to the actual property
+  name, then related properties are moved to the place where their group
+  tag appears first. The first grouped property gets a "- " prefix, all
+  following ones are just indended with "  ". The actual group tag is not
+  part of the normalized output, because its value is irrelevant:
+
+  BDAY:19701230
+  - EMAIL:john@custom.com
+    X-ABLabel:custom-label2
+  ...
+  FN:Mr. John 1 Doe Sr.
+  - IMPP;X-SERVICE-TYPE=AIM:aim:aim
+    X-ABLabel:Other
+  ...
+  - X-ABDATE:19710101
+    X-ABLabel:Anniversary
+
+  Redundant tags (those set for only a single property, X-ABLabel:Other)
+  get removed as part of normalizing an item.
+
+* WebDAV: use server's order when listing collections
+
+  When doing a recursive scan of the home set, preserve the order of
+  entries as reported by the server and check the first one first. The
+  server knows better which entries are more relevant for the user (and
+  thus should be the default) or may have some other relevant
+  order. Previously, SyncEvolution replaced that order with sorting by
+  URL, which led to a predictable, but rather meaningless order.
+
+  For example, Google lists the users own calendar first, followed by
+  the shared calendars sorted alphabetical by their name. Now
+  SyncEvolution picks the main calendar as default correctly when
+  scanning from https://www.google.com/calendar/dav/.
+
+* WebDAV: improved database search (Google, Zimbra)
+
+  Zimbra has a principal URL that also serves as home set. When using it
+  as start URL, SyncEvolution only looked the URL once, without listing
+  its content, and thus did not find the databases.
+
+  When following the Zimbra principal URL indirectly, SyncEvolution did
+  check all of the collections there recursively. Unfortunately that
+  also includes many mail folders, causing the scan to abort after
+  checking 1000 collections (an internal safe guard).
+
+  The solution for both includes tracking what to do with a URL. For the
+  initial URL, only meta data about the URL itself gets
+  checked. Recursive scanning is only done for the home set. If that
+  home set contains many collections, scanning is still slow and may run
+  into the internal safe guard limit. This cannot be avoided because the
+  CalDAV spec explicitly states that the home set may contain normal
+  collections which contain other collections, so a client has to do the
+  recursive scan.
+
+  When looking at a specific calendar, Google CalDAV does not report
+  what the current principal or the home set is and therefore
+  SyncEvolution stopped after finding just the initial calendar. Now it
+  detects the lack of meta information and adds all parents also as
+  candidates that need to be looked at. The downside of this is that it
+  doesn't know anything about which parents are relevant, so it ends up
+  checking https://www.google.com/calendar/ and
+  https://www.google.com/.
+
+  In both cases Basic Auth gets rejected with a temporary redirect to
+  the Google login page, which is something that SyncEvolution must
+  ignore immediately during scanning without applying the resend
+  workaround for "temporary rejection of valid credentials" that can
+  happen for valid Google CalDAV URLs.
+
+* WebDAV: enhanced database search (Google Calendar)
+
+  Additional databases where not found for several
+  reasons. SyncEvolution ignored all shared calendars
+  (http://calendarserver.org/ns/shared) and Google marks the additional
+  calendars that way. The other problem was that the check for leaf
+  collections (= collections which cannot contain other desired
+  collections) incorrectly excluded those collections instead of only
+  preventing listing of their content.
+
+  With this change,
+  https://www.google.com/calendar/dav/?SyncEvolution=Google can be used
+  as starting point for Google Calendar.
+
+* WebDAV: fix database scan on iCloud
+
+  The calendar home set URL on iCloud (the one ending in /calendars/) is
+  declared as containing calendar data. That was enough for
+  SyncEvolution to accept it incorrectly as calendar. However, the home
+  set only contains calendar data indirectly.
+
+* WebDAV: support redirects between hosts and DNS SRV lookup based on URL
+
+  When finding a new URL, we must be prepared to reinitialize the Neon
+  session with the new host settings.
+
+  iCloud does not have .well-known support on its www.icloud.com
+  server. To support lookup with a non-icloudd.com email address, we
+  must do DNS SRV lookup when access to .well-known URLs fails. We do
+  this without a www prefix on the host first, because that is what happens
+  to work for icloud.com.
+
+  With these changes it becomes possible to do database scans on Apple
+  iCloud, using syncURL=https://www.icloud.com or
+  syncURL=https://icloud.com. Giving the syncURL like this is only
+  necessary for a username that does not end in @icloud.com. When
+  the syncURL is not set, the domain for DNS SRV lookup is taken
+  from the username.
+
+* WebDAV: more efficient item creation
+
+  PUT has the disadvantage that a client needs to choose a name and then
+  figure out what the real name on the server is. With Google CardDAV that
+  requires sending another request and only works because the server happens
+  to remember the original name (which is not guaranteed!).
+
+  POST works for new items without a name and happens to be implemented
+  by Google such that the response already includes all required
+  information (new name and revision string).
+
+  POST is checked for as described in RFC 5995 once before creating a new
+  item. Servers which don't support it continue to get a PUT.
+
+* WebDAV: send "User-Agent: SyncEvolution"
+
+  Apple iCloud servers reject requests unless they contain a User-Agent
+  header. The exact value doesn't seem to matter. Making the string
+  configurable might be better, but can still be done later when it
+  is more certain whether and for what it is needed.
+
+* WebDAV: refactor and fix DNS SRV lookup
+
+  The syncevo-webdav-lookup script was not packaged. It did not report
+  "not found" DNS results correctly and the caller did not check for
+  this either, so when looking up the information for a domain which
+  does not have DNS SRV entries, SyncEvolution ended up retrying for
+  while as if there had been a temporary lookup problem.
+
+* Google: remove SyncML template, combine CalDAV/CardDAV
+
+  Google has turned off their SyncML server, so the corresponding
+  "Google Contacts" template became useless and needs to be removed. It
+  gets replaced by a "Google" template which combines the three
+  different URLs currently used by Google for CalDAV/CardDAV.
+
+  This new template can be used to configure a "target-config@google"
+  with default calendar and address book database already enabled. The
+  actual URL of these databases will be determined during the first
+  sync using them.
+
+  The template relies on the WebDAV backend's new capability to search
+  multiple different entries in the syncURL property for databases. To
+  avoid listing each calendar twice (once for the legacy URL, once with
+  the new one) when using basic username/password authentication, the
+  backend needs a special case for Google and detect that the legacy URL
+  does not need to be checked.
+
+* Google Calendar: remove child hack, improve alarm hack (FDO #63881)
+
+  Google recently enhanced support for RECURRENCE-ID, so SyncEvolution
+  no longer needs to replace the property when uploading a single
+  detached event with RECURRENCE-ID. However, several things are still
+  broken in the server, with no workaround in SyncEvolution:
+  - Removing individual events gets ignored by the server;
+    a full "wipe out server data" might work (untested).
+  - When updating the parent event, all child events also get
+    updated even though they were included unchanged in the data
+    sent by SyncEvolution.
+  - The RECURRENCE-ID of a child event of an all-day recurring event
+    does not get stored properly.
+  - The update hack seems to fail for complex meetings: uploading them
+    once and then deleting them seems to make uploading them again
+    impossible.
+
+  All of these issues were reported to Google and are worked on there,
+  so perhaps the situation will improve. In the meantime, syncing with
+  Google CalDAV should better be limited to:
+  - Downloading a Google calendar in one-way mode.
+  - Two-way syncing of simple calendars without complex meeting
+    serieses.
+
+  While updating the Google workarounds, the alarm hack (sending a
+  new event without alarms twice to avoid the automatic server side
+  alarm) was simplified. Now the new event gets sent only once with a
+  pseudo-alarm.
+
+* CardDAV: implement read-ahead
+
+  Instead of downloading contacts one-by-one with GET, SyncEvolution now
+  looks at contacts that are most likely going to be needed soon and
+  gets all of them at once with addressbook-multiget REPORT.
+
+  The number of contacts per REPORT is 50 by default, configurable by
+  setting the SYNCEVOLUTION_CARDDAV_BATCH_SIZE env variable.
+
+  This has two advantages:
+  - It avoids round-trips to the server and thus speeds up a large
+    download (100 small contacts with individual GETs took 28s on
+    a fast connection, 3s with two REPORTs).
+  - It reduces the overall number of requests. Google CardDAV is known
+    to start issuing intermittent 401 authentication errors when the
+    number of contacts retrieved via GET is too large. Perhaps this
+    can be avoided with addressbook-multiget.
+
+* oauth2: new backend using libsoup/libcurl
+
+  New backend implements identity provider for obtaining OAuth2 access
+  token for systems without HMI support.
+  Access token is obtained by making direct HTTP request to OAuth2 server
+  and using refresh token obtained by user in some other way.
+  New provider automatically updates stored refresh token when OAuth2
+  server is issuing new one.
+
+* signon: make Accounts optional
+
+  The new "signon" provider only depends on lib[g]signon-glib. It uses
+  gSSO if found, else UOA. Instead of pulling parameters and the
+  identity via libaccounts-glib, the user of SyncEvolution now has to
+  ensure that the identity exists and pass all relevant parameters
+  in the "signon:" username.
+
+* gSSO: adapt to gSSO >= 2.0
+
+* signon: fix build
+
+  Static build was broken for gSSO and UOA (wrong path name to .la file)
+  and gSSO was not enabled properly (wrong condition check).
+
+* datatypes: raw text items with minimal conversion (FDO #52791)
+
+  When using "raw/text/calendar" or "raw/text/vcard" as SyncEvolution
+  "databaseFormat", all parsing and conversion is skipped. The backend's
+  data is identical to the item data in the engine. Finding duplicates
+  in a slow sync is very limited when using these types because the entire
+  item data must match exactly.
+
+  This is useful for the file backend when the goal is to store an exact copy
+  of what a peer has or for limited, read-only backends (PBAP). The downside
+  of using the raw types is that the peer is not given accurate information
+  about which vCard or iCalendar properties are supported, which may cause
+  some peers to not send all data.
+
+* datatypes: text/calendar+plain revised heuristic
+
+  When sending a VEVENT, DESCRIPTION was set to the SUMMARY if empty. This may
+  have been necessary for some peers, but for notes (= VJOURNAL) we don't know
+  that (hasn't been used in the past) and don't want to alter the item
+  unnecessarily, so skip that part and allow empty DESCRIPTION.
+
+  When receiving a plain text note, the "text/calendar+plain" type
+  used to store the first line as summary and the rest as description.
+  This may be correct in some cases and wrong in others.
+
+  The EDS backend implemented a different heuristic: there the first
+  line is copied into the summary and stays in the description. This
+  makes a bit more sense (the description alone is always enough to
+  understand the note). Therefore and to avoid behavioral changes
+  for EDS users when switching the EDS backend to use text/calendar+plain,
+  the engine now uses the same approach.
+
+* datatypes: avoid PHOTO corruption during merge (FDO #77065)
+
+  When handling an update/update conflict (both sides of the sync have an
+  updated contact) and photo data was moved into a local file by EDS, the engine
+  merged the file path and the photo data together and thus corrupted the photo.
+
+  The engine does not know about the special role of the photo property.
+  This needs to be handled by the merge script, and that script did not
+  cover this particular situation. Now the loosing side is cleared,
+  causing the engine to then copy the winning side over into the loosing
+  one.
+
+  Found by Renato Filho/Canonical when testing SyncEvolution for Ubuntu 14.04.
+
+* vcard profile: avoid data loss during merging
+
+  When resolving a merge conflict, repeating properties were taken
+  wholesale from the winning side (for example, all email addresses). If
+  a new email address had been added on the loosing side, it got lost.
+
+  Arguably it is better to preserve as much data as possible during a
+  conflict. SyncEvolution now does that in a merge script by checking
+  which properties in the loosing side do not exist in the winning side
+  and copying those entries.
+
+  Typically only the main value (email address, phone number) is checked
+  and not the additional meta data (like the type). Otherwise minor
+  differences (for example, both sides have same email address, but with
+  different types) would lead to duplicates.
+
+  Only addresses are treated differently: for them all attributes
+  (street, country, city, etc.) are compared, because there is no single
+  main value.
+
+* engine: UID support in contact data
+
+  Before, the UID property in a vCard was ignored by the engine.
+  Backends were responsible for ensuring that the property is
+  set if required by the underlying storage. This turned out to be
+  handled incompletely in the WebDAV backend.
+
+  This change moves this into the engine:
+  - UID is now field. It does not get used for matching
+    because the engine cannot rely on it being stored
+    by both sides.
+  - It gets parsed if present, but only generated if
+    explicitly enabled (because that is the traditional
+    behavior).
+  - It is never shown in the DevInf's CtCap
+    because the Synthesis engine would always show it
+    regardless whether a rule enabled the property.
+    That's because rules normally only get triggered
+    after exchanging DevInf and thus DevInf has to
+    be rule-independent. We don't want it shown because
+    then merging the incoming item during a local sync
+    would use the incoming UID, even if it is empty.
+  - Before writing, ensure that UID is set.
+
+  When updating an existing item, the Synthesis engine reads
+  the existing item, preserves the existing UID unless the peer
+  claims to support UID, and then updates with the existing UID.
+
+  This works for local sync (where SyncEvolution never claims
+  to support UID when talking to the other side). It will break
+  with peers which have UID in their CtCap although they
+  rewrite the UID and backends whose underlying storage cannot
+  handle UID changes during an update (for example, CardDAV).
+
+* engine: flush map items less frequently
+
+  The Synthesis API does not say explicitly, but in practice all map
+  items get updated in a tight loop. Rewriting the m_mappingNode (case
+  insensitive string comparisons) and serialization to disk
+  (std::ostrstream) consume a significant amount of CPU cycles and cause
+  extra disk writes that can be avoided by making some assumptions about
+  the sequence of API calls and flushing only once.
+
+* local sync: exchange SyncML messages via shared memory
+
+  Encoding/decoding of the uint8_t array in D-Bus took a surprisingly
+  large amount of CPU cycles relative to the rest of the SyncML message
+  processing. Now the actual data resides in memory-mapped temporary
+  files and the D-Bus messages only contain offset and size inside these
+  files. Both sides use memory mapping to read and write directly.
+
+  For caching 1000 contacts with photos on a fast laptop, total sync
+  time roughly drops from 6s to 3s.
+
+  To eliminate memory copies, memory handling in libsynthesis or rather,
+  libsmltk is tweaked such that it allocates the buffer used for SyncML
+  message data in the shared memory buffer directly. This relies on
+  knowledge of libsmltk internals, but those shouldn't change and if they
+  do, SyncEvolution will notice ("unexpected send buffer").
+
+* local sync: avoid updating meta data when nothing changed
+
+  The sync meta data (sync anchors, client change log) get updated after
+  a sync even if nothing changed and the existing meta data could be
+  used again. This can be skipped for local sync, because then
+  SyncEvolution can ensure that both sides skip updating the meta
+  data. With a remote SyncML server that is not possible and thus
+  SyncEvolution has to update its data.
+
+  It is based on the observation that when the server side calls
+  SaveAdminData, the client has sent its last message and the sync is
+  complete. At that point, SyncEvolution can check whether anything has
+  changed and if not, skip saving the server's admin data and stop the
+  sync without sending the real reply to the client.
+
+  Instead the client gets an empty message with "quitsync" as content
+  type. Then it takes shortcuts to close down without finalizing the
+  sync engine, because that would trigger writing of meta data
+  changes. The server continues its shutdown normally.
+
+  This optimization is limited to syncs with a single source, because
+  the assumption about when aborting is possible is harder to verify
+  when multiple sources are involved.
+
+* PBAP: support SYNCEVOLUTION_PBAP_CHUNK_TRANSFER_TIME <= 0
+
+  When set to 0 or less, the chunk size is not getting adapted at all
+  while still using transfers in chunks.
+
+* PBAP: use raw text items
+
+  This avoids the redundant parse/generate step on the sending
+  side of the PBAP sync.
+
+* PBAP syncing: updated photo not always stored
+
+  Because photo data was treated like a C string, changes after any
+  embedded null byte were ignored during a comparison.
+
+* ephemeral sync: don't write binfile client files (FDO #55921)
+
+  When doing PBAP caching, we don't want any meta data written because
+  the next sync would not use it anyway. With the latest libsynthesis
+  we can configure "/dev/null" as datadir for the client's binfiles and
+  libsynthesis will avoid writing them.
+
+  The PIM manager uses this for PBAP syncing automatically. For testing
+  it can be enabled by setting the SYNCEVOLUTION_EPHEMERAL env variable.
+
+* PBAP: avoid empty field filter
+
+  Empty field filter is supposed to mean "return all supported
+  fields". This used to work and stopped working with Android phones
+  after an update to 4.3 (seen on Galaxy S3); now the phone only
+  returns the mandatory TEL, FN, N fields.
+
+  The workaround is to replace the empty filter list with the list of
+  known and supported properties. This means we only pull data we really
+  need, but it also means we won't get to see any additional properties
+  that the phone might support.
+
+* PBAP: transfer in chunks (FDO #77272)
+
+  If enabled via env variables, PullAll transfers will be limited to
+  a certain numbers contacts at different offsets until all data got
+  pulled. See PBAP README for details.
+
+  When transfering in chunks, the enumeration of contacts for the engine
+  no longer matches the PBAP enumeration. Debug output uses "offset #x"
+  for PBAP and "ID y" for the engine.
+
+* PBAP: remove transfer via pipe
+
+  Using a pipe was never fully supported by obexd (blocks
+  obexd). Transfering in suitably sized chunks (FDO #77272) will be a
+  more obexd friendly solution with a similar effect (not having to
+  buffer the entire address book in memory).
+
+* PBAP: Suspend/ResumeSync() (FDO #72112)
+
+  By default, the new API freezes a sync by stopping to consume data on the
+  local side of the sync.
+
+  In addition, the information that the sync is freezing is now also handed
+  down to the transport and all sources. In the case of PBAP caching, the local
+  transport notifies the child where the PBAP source then uses Bluez
+  5.15 Transfer1.Suspend/Resume to freeze/thaw the actual OBEX transfer.
+
+  If that fails (for example, not implemented because Bluez is too old
+  or the transfer is still queueing), then the transfer gets cancelled
+  and the entire sync fails. This is desirable for PBAP caching and
+  Bluetooth because a failed sync can easily be recovered from (just
+  start it again) and the overall goal is to free up Bluetooth bandwidth
+  quickly.
+
+* PBAP: transfer data via pipe (part of FDO #72112)
+
+  The main advantage is that processed data can be discarded
+  immediately. When using a plain file, the entire address book must be
+  stored in it.
+
+  The drawback is that obexd does not react well to a full pipe. It
+  simply gets stuck in a blocking write(); in other words, all obexd
+  operations get frozen and obexd stops responding on D-Bus.
+
+* PIM: include CardDAV in CreatePeer()
+
+  This adds "protocol: CardDAV" as a valid value, with corresponding
+  changes to the interpretation of some existing properties and some new
+  ones. The API itself is not changed.
+
+  Suspending a CardDAV sync is possible. This freezes the internal
+  SyncML message exchange, so data exchange with the CardDAV server may
+  continue for a while after SuspendPeer().
+
+  Photo data is always downloaded immediately. The "pbap-sync" flag
+  in SyncPeerWithFlags() has no effect.
+
+  Syncing can be configured to be one-way (local side is read-only
+  cache) or two-way (local side is read/write). Meta data must be
+  written either way, to speed up caching or allow two-way syncing. The
+  most common case (no changes on either side) will have to be optimized
+  such that existing meta data is not touched and thus no disk writes
+  occur.
+
+* PIM: handle SuspendPeer() before and after transfer (FDO #82863)
+
+  A SuspendPeer() only succeeded while the underlying Bluetooth transfer
+  was active. Outside of that, Bluez errors caused SyncEvolution to
+  attempt a cancelation of the transfer and stopped the sync.
+
+  When the transfer was still queueing, obexd returns
+  org.bluez.obex.Error.NotInProgress. This is difficult to handle for
+  SyncEvolution: it cannot prevent the transfer from starting and has to
+  let it become active before it can suspend the transfer. Canceling
+  would lead to difficult to handle error cases (like partially parsed
+  data) and therefore is not done.
+
+  The Bluez team was asked to implement suspending of queued transfers
+  (see "org.bluez.obex.Transfer1 Suspend/Resume in queued state" on
+  linux-bluetooth@vger.kernel.org), so this case might not happen
+  anymore with future Bluez.
+
+  When the transfer completes before obexd processes the Suspend(),
+  org.freedesktop.DBus.Error.UnknownObject gets returned by
+  obexd. SyncEvolution can ignore errors which occur after the active
+  transfer completed. In addition, it should prevent starting the next
+  one. This may be relevant for transfer in chunks, although the sync
+  engine will also stop asking for data and thus typically no new
+  transfer gets triggered anyway.
+
+* PIM: add suspend/resume/abort to sync.py
+
+  CTRL-C while waiting for the end of a sync causes an interactive
+  prompt to appear where one can choose been suspend/resume/abort and
+  continuing to wait. CTRL-C again in the prompt aborts the script.
+
+* PIM: enhanced progress notifications (FDO #72114)
+
+  This adds GetPeerStatus() and "progress" events. Progress is reported based
+  on the "item received" Synthesis event and the total item count. A modified
+  libsynthesis is needed where the SyncML binfile client on the target side of
+  the local sync actually sends the total item count (via NumberOfChanges).
+  This cannot be done yet right at the start of the sync, only the second SyncML
+  message will have it. That is acceptable, because completion is reached very
+  quickly anyway for syncs involving only one message.
+
+  At the moment, SyncContext::displaySourceProgress() holds back "item
+  received" events until a different event needs to be emitted. Progress
+  reporting might get more fine-grained when adding allowing held back
+  events to be emitted at a fixed rate, every 0.1s. This is not done yet
+  because it seems to work well enough already.
+
+  For testing and demonstration purposes, sync.py gets command line
+  arguments for setting progress frequency and showing progress either
+  via listening to signals or polling.
+
+* PIM: add SyncPeerWithFlags() and 'pbap-sync' flag (FDO #70950)
+
+  The is new API and flag grant control over the PBAP sync mode.
+
+* PIM: fix phone number normalization
+
+  The parsed number always has a country code, whereas SyncEvolution expected it
+  to be zero for strings without an explicit country code. This caused a caller
+  ID lookup of numbers like "089788899" in DE to find only telephone numbers in
+  the current default country, instead of being more permissive and also finding
+  "+189788899". The corresponding unit test was broken and checked for the wrong
+  result. Found while investigating an unrelated test failure when updating
+  libphonenumber.
+
+* engine: enable batching by default (FDO #52669)
+
+  This reverts commit c435e937cd406e904c437eec51a32a6ec6163102.
+
+  Commit 7b636720a in libsynthesis fixes an unitialized memory read in
+  the asynchronous item update code path.
+
+  Testing confirms that we can now used batched writes reliably with EDS
+  (the only backend currently supporting asynchronous writes +
+  batching), so this change enables it again also for local and
+  SyncEvolution<->SyncEvolution sync (with asynchronous execution of
+  contact add/update overlapped with SyncML message exchanges) and other
+  SyncML syncs (with changes combined into batches and executed at the
+  end of each message).
+
+* Various compiler problems and warnings fixed; compiles with
+  --with-warnings=fatal on current Debian Testing and Ubuntu Trusty
+  (FDO #79316).
+
+* D-Bus server: fix unreliable shutdown handling
+
+  Occassionally, syncevo-dbus-server locked up after receiving
+  a CTRL-C. This primarily affected nightly testing, in particular (?)
+  on Ubuntu Lucid.
+
+* D-Bus: use streams for direct IPC with GIO
+
+  When using GIO, it is possible to avoid the DBusServer listening on a
+  publicly accessible address. Connection setup becomes more reliable,
+  too, because the D-Bus server side can detect that a child died
+  because the connection will be closed.
+
+  When using libdbus, the traditional server/listen and client/connect
+  model is still used.
+
+* LogRedirect: safeguard against memory corruption
+
+  When aborting, our AbortHandler gets called to close down logging.
+  This may involve memory allocation, which is unsafe. In FDO #76375, a
+  deadlock on a libc mutex was seen.
+
+  To ensure that the process shuts down anyway, install an alarm and give
+  the process five seconds to shut down before the SIGALRM signal will kill
+  it.
+
+
+Upgrading from releases <= 1.3.99.4:
+
+If the value of "username/databaseUser/proxyUser" contains a colon,
+the "user:" prefix must be added to the value, to continue treating it
+like a plain user name and not some reference to an unknown identity
+provider (like "id:", "goa:", "signon:", etc.).
+
+The lookup of passwords in GNOME Keyring was updated slightly in
+1.3.99.5. It may be necessary to set passwords anew if the old one is
+no longer found.
+
+Upgrading from release 1.2.x:
+
+The sync format of existing configurations for Mobical (aka Everdroid)
+must be updated manually, because the server has encoding problems when
+using vCard 3.0 (now the default for Evolution contacts):
+   syncevolution --configure \
+                 syncFormat=text/x-vcard \
+                 mobical addressbook
+
+The Funambol template explicitly enables usage of the
+"refresh-from-server" sync mode to avoid getting throttled with 417
+'retry later' errors. The same must be added to existing configs
+manually:
+   syncevolution --configure \
+                 enableRefreshSync=TRUE \
+                 funambol
+
+Upgrading from releases before 1.2:
+
+Old configurations can still be read. But writing, as it happens
+during a sync, must migrate the configuration first. Releases >= 1.2
+automatically migrates configurations. The old configurations
+will still be available (see "syncevolution --print-configs") but must
+be renamed manually to use them again under their original names with
+older SyncEvolution releases.
+
+
+SyncEvolution 1.4.99.4 -> 1.5, 31.10.2014
+=========================================
+
+Mostly a bug fix release.
+
+Details:
+
+* vcard: fix caching of PBAP contacts (FDO #84710)
+
+  After changing PBAP to send raw items, caching them led to unnecessary
+  disk writes and bogus "contacts changed" reports. That's because
+  the merge script relied on the exact order of properties, which was
+  only the same when doing the redundant decode/encode on the PBAP side.
+
+  Instead of reverting back to sending re-encoded items, better enhance
+  the contact merge script such that it detects contacts as unchanged
+  when just the order of entries in the property arrays is different.
+  This relies on an enhanced libsynthesis with the new RELAXEDCOMPARE()
+  and modified MERGEFIELDS().
+
+* sync: ignore unnecessary username property
+
+  A local sync or Bluetooth sync do not need the 'username' property.
+  When it is set despite that, issue a warning.
+
+  Previously, the value was checked even when not needed, which
+  caused such syncs to fail when set to something other than a plain
+  username.
+
+* D-Bus server: fix unreliable shutdown handling
+
+  Occassionally, syncevo-dbus-server locked up after receiving
+  a CTRL-C. This primarily affected nightly testing, in particular (?)
+  on Ubuntu Lucid.
+
+* scripting: prevent premature loop timeouts
+
+  The more complex "avoid data loss during merging" scripting ran for longer
+  than 5s limit under extreme conditions (full logging, busy system, running
+  under valgrind), which resulted in aborting the script and a 10500 "local
+  internal error" sync failure.
+
+* signon: fix providersignon.so (TC-1667)
+
+  The shared providersignon.so ended up being compiled with "gsso" as
+  prefix for the username. There also was a problem with invalid
+  reference counting.
+
+* PBAP: support SYNCEVOLUTION_PBAP_CHUNK_TRANSFER_TIME <= 0
+
+  When set to 0 or less, the chunk size is not getting adapted at all
+  while still using transfers in chunks.
+
+
 SyncEvolution 1.4.99.3 -> 1.4.99.4, 10.09.2014
 ==============================================
 
diff --git a/README b/README
index 55bc2cd..521371c 100644 (file)
--- a/README
+++ b/README
@@ -7,8 +7,8 @@ synchronize personal information management data
 ------------------------------------------------
 
 :Manual section: 1
-:Version: 1.4.99.4
-:Date: 2014-09-12
+:Version: 1.5
+:Date: 2014-10-31
 
 
 SYNOPSIS
index e9dd81b..fab4e49 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for syncevolution 1.4.99.4.
+# Generated by GNU Autoconf 2.69 for syncevolution 1.5.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='syncevolution'
 PACKAGE_TARNAME='syncevolution'
-PACKAGE_VERSION='1.4.99.4'
-PACKAGE_STRING='syncevolution 1.4.99.4'
+PACKAGE_VERSION='1.5'
+PACKAGE_STRING='syncevolution 1.5'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1765,7 +1765,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.4.99.4 to adapt to many kinds of systems.
+\`configure' configures syncevolution 1.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1835,7 +1835,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of syncevolution 1.4.99.4:";;
+     short | recursive ) echo "Configuration of syncevolution 1.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1843,12 +1843,12 @@ Optional Features:
   --disable-option-checking  ignore unrecognized --enable/--with options
   --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
-  --enable-release-mode   Controls whether resulting binary is for end-users
+  --disable-release-mode  Controls whether resulting binary is for end-users
                           or testers/developers. For example, stable releases
                           automatically migrate on-disk files without asking,
                           whereas other releases ask before making downgrades
                           impossible (or difficult). Default in this source
-                          code is "stable release: no"
+                          code is "stable release: yes"
   --enable-silent-rules          less verbose build output (undo: `make V=1')
   --disable-silent-rules         verbose build output (undo: `make V=0')
   --disable-dependency-tracking  speeds up one-time build
@@ -2309,7 +2309,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-syncevolution configure 1.4.99.4
+syncevolution configure 1.5
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2949,7 +2949,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.4.99.4, which was
+It was created by syncevolution $as_me 1.5, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3336,6 +3336,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
+
 # Minimum version of libsynthesis as defined in its
 # configure script and thus .pc files:
 
@@ -3348,7 +3349,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 if test "${enable_release_mode+set}" = set; then :
   enableval=$enable_release_mode; enable_release_mode="$enableval"
 else
-  enable_release_mode="no"
+  enable_release_mode="yes"
 fi
 
 if test "$enable_release_mode" = "yes"; then
@@ -3863,7 +3864,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='syncevolution'
- VERSION='1.4.99.4'
+ VERSION='1.5'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -21301,12 +21302,12 @@ if test -n "$SYNTHESIS_CFLAGS"; then
     pkg_cv_SYNTHESIS_CFLAGS="$SYNTHESIS_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.4\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.4") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.5\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.5") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_SYNTHESIS_CFLAGS=`$PKG_CONFIG --cflags "synthesis >= 3.4.0.47.4" 2>/dev/null`
+  pkg_cv_SYNTHESIS_CFLAGS=`$PKG_CONFIG --cflags "synthesis >= 3.4.0.47.5" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -21318,12 +21319,12 @@ if test -n "$SYNTHESIS_LIBS"; then
     pkg_cv_SYNTHESIS_LIBS="$SYNTHESIS_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.4\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.4") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.5\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.5") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_SYNTHESIS_LIBS=`$PKG_CONFIG --libs "synthesis >= 3.4.0.47.4" 2>/dev/null`
+  pkg_cv_SYNTHESIS_LIBS=`$PKG_CONFIG --libs "synthesis >= 3.4.0.47.5" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -21344,14 +21345,14 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               SYNTHESIS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "synthesis >= 3.4.0.47.4" 2>&1`
+               SYNTHESIS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "synthesis >= 3.4.0.47.5" 2>&1`
         else
-               SYNTHESIS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "synthesis >= 3.4.0.47.4" 2>&1`
+               SYNTHESIS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "synthesis >= 3.4.0.47.5" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
        echo "$SYNTHESIS_PKG_ERRORS" >&5
 
-       as_fn_error $? "Package requirements (synthesis >= 3.4.0.47.4) were not met:
+       as_fn_error $? "Package requirements (synthesis >= 3.4.0.47.5) were not met:
 
 $SYNTHESIS_PKG_ERRORS
 
@@ -21438,12 +21439,12 @@ if test -n "$WITH_SYNTHESIS_SRC_CFLAGS"; then
     pkg_cv_WITH_SYNTHESIS_SRC_CFLAGS="$WITH_SYNTHESIS_SRC_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.4\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.4") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.5\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.5") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_WITH_SYNTHESIS_SRC_CFLAGS=`$PKG_CONFIG --cflags "synthesis >= 3.4.0.47.4" 2>/dev/null`
+  pkg_cv_WITH_SYNTHESIS_SRC_CFLAGS=`$PKG_CONFIG --cflags "synthesis >= 3.4.0.47.5" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -21455,12 +21456,12 @@ if test -n "$WITH_SYNTHESIS_SRC_LIBS"; then
     pkg_cv_WITH_SYNTHESIS_SRC_LIBS="$WITH_SYNTHESIS_SRC_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.4\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.4") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"synthesis >= 3.4.0.47.5\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "synthesis >= 3.4.0.47.5") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_WITH_SYNTHESIS_SRC_LIBS=`$PKG_CONFIG --libs "synthesis >= 3.4.0.47.4" 2>/dev/null`
+  pkg_cv_WITH_SYNTHESIS_SRC_LIBS=`$PKG_CONFIG --libs "synthesis >= 3.4.0.47.5" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -21481,18 +21482,18 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               WITH_SYNTHESIS_SRC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "synthesis >= 3.4.0.47.4" 2>&1`
+               WITH_SYNTHESIS_SRC_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "synthesis >= 3.4.0.47.5" 2>&1`
         else
-               WITH_SYNTHESIS_SRC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "synthesis >= 3.4.0.47.4" 2>&1`
+               WITH_SYNTHESIS_SRC_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "synthesis >= 3.4.0.47.5" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
        echo "$WITH_SYNTHESIS_SRC_PKG_ERRORS" >&5
 
-       as_fn_error $? "need at least libsynthesis >= 3.4.0.47.4; the latest libsynthesis for SyncEvolution is the one from http://cgit.freedesktop.org/SyncEvolution/" "$LINENO" 5
+       as_fn_error $? "need at least libsynthesis >= 3.4.0.47.5; the latest libsynthesis for SyncEvolution is the one from http://cgit.freedesktop.org/SyncEvolution/" "$LINENO" 5
 elif test $pkg_failed = untried; then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       as_fn_error $? "need at least libsynthesis >= 3.4.0.47.4; the latest libsynthesis for SyncEvolution is the one from http://cgit.freedesktop.org/SyncEvolution/" "$LINENO" 5
+       as_fn_error $? "need at least libsynthesis >= 3.4.0.47.5; the latest libsynthesis for SyncEvolution is the one from http://cgit.freedesktop.org/SyncEvolution/" "$LINENO" 5
 else
        WITH_SYNTHESIS_SRC_CFLAGS=$pkg_cv_WITH_SYNTHESIS_SRC_CFLAGS
        WITH_SYNTHESIS_SRC_LIBS=$pkg_cv_WITH_SYNTHESIS_SRC_LIBS
@@ -26717,7 +26718,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.4.99.4, which was
+This file was extended by syncevolution $as_me 1.5, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -26783,7 +26784,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.4.99.4
+syncevolution config.status 1.5
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index cea60f7..7c4b05f 100644 (file)
@@ -8,7 +8,7 @@ dnl Invoke autogen.sh to produce a configure script.
 #
 # Starting with the 1.1 release cycle, the rpm-style
 # .99 pseudo-version number is used to mark a pre-release.
-AC_INIT([syncevolution], [m4_esyscmd([build/gen-git-version.sh 1.4.99.4])])
+AC_INIT([syncevolution], [m4_esyscmd([build/gen-git-version.sh 1.5])])
 # STABLE_VERSION=1.0.1+
 AC_SUBST(STABLE_VERSION)
 
@@ -25,7 +25,7 @@ SE_CHECK_FOR_STABLE_RELEASE
 
 # Minimum version of libsynthesis as defined in its
 # configure script and thus .pc files:
-define([SYNTHESIS_MIN_VERSION], [3.4.0.47.4])
+define([SYNTHESIS_MIN_VERSION], [3.4.0.47.5])
 
 # Line above is patched by gen-autotools.sh. Handle
 # both "yes" and "no".
index 05aa832..cfa46eb 100644 (file)
@@ -983,7 +983,8 @@ bool PullAll::getContact(const char *id, pcrecpp::StringPiece &vcard)
             // time. Ignore clipped or suspended transfers, they are
             // not representative. Also avoid completely bogus
             // observations.
-            if (!m_wasSuspended &&
+            if (m_pullParams.m_timePerChunk > 0 &&
+                !m_wasSuspended &&
                 m_transferMaxCount == m_desiredMaxCount &&
                 m_lastTransferRate > 0 &&
                 m_lastContactSizeAverage > 0) {
index e473c69..164e7a5 100644 (file)
@@ -97,9 +97,7 @@ public:
         // so we have to use the "steal" variant to enable that assignment.
         GVariantStealCXX resultDataVar;
         GErrorCXX gerror;
-        // Enforce normal reference counting via _ref_sink.
-        GVariantCXX sessionDataVar(g_variant_ref_sink(HashTable2Variant(m_sessionData)),
-                                   TRANSFER_REF);
+        GVariantCXX sessionDataVar(HashTable2Variant(m_sessionData));
         PlainGStr buffer(g_variant_print(sessionDataVar, true));
         SE_LOG_DEBUG(NULL, "asking for OAuth2 token with method %s, mechanism %s and parameters %s",
                      signon_auth_session_get_method(m_authSession),
index c34803a..8f8c0e0 100644 (file)
@@ -36,14 +36,14 @@ public:
         // one to use. If it turns out that the two will never be installed at the
         // same time, then this perhaps should be "signon" instead, which then would
         // pick either a gSSO or UAO backend depending on which is available.
-#if defined(USE_GSSO) || defined(STATIC_GSSO)
+#if defined(USE_ACCOUNTS) && defined(USE_GSSO) || defined(STATIC_GSSO)
         IdentityProvider("gsso",
                          "gsso:<numeric account ID>[,<service name>]\n"
                          "   Authentication using libgsignond + libaccounts,\n"
                          "   using an account created and managed with libaccounts.\n"
                          "   The service name is optional. If not given, the\n"
                          "   settings from the account will be used.")
-#elif defined(USE_UOA) || defined(STATIC_UOA)
+#elif defined(USE_ACCOUNTS) && defined(USE_UOA) || defined(STATIC_UOA)
         IdentityProvider("uoa",
                          "uoa:<numeric account ID>[,<service name>]\n"
                          "   Authentication using libsignon + libaccounts,\n"
index 201edb9..8f54ec7 100644 (file)
@@ -45,16 +45,8 @@ using namespace GDBusCXX;
 
 namespace {
     GMainLoop *loop = NULL;
-    bool shutdownRequested = false;
     const char * const execName = "syncevo-dbus-server";
 
-void niam(int sig)
-{
-    shutdownRequested = true;
-    SuspendFlags::getSuspendFlags().handleSignal(sig);
-    g_main_loop_quit (loop);
-}
-
 bool parseDuration(int &duration, const char* value)
 {
     if(value == NULL) {
@@ -189,10 +181,6 @@ int main(int argc, char **argv, char **envp)
         // process name for developers in this process, and not in
         // syncevo-dbus-helper.
         Logger::setProcessName("syncevo-dbus-server");
-
-        SE_LOG_DEBUG(NULL, "syncevo-dbus-server: catch SIGINT/SIGTERM in our own shutdown function");
-        signal(SIGTERM, niam);
-        signal(SIGINT, niam);
         boost::shared_ptr<SuspendFlags::Guard> guard = SuspendFlags::getSuspendFlags().activate();
 
         DBusErrorCXX err;
@@ -206,7 +194,7 @@ int main(int argc, char **argv, char **envp)
         // make this object the main owner of the connection
         boost::scoped_ptr<DBusObject> obj(new DBusObject(conn, "foo", "bar", true));
 
-        boost::shared_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, shutdownRequested, restart, conn, duration));
+        boost::shared_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, restart, conn, duration));
         server->setDBusLogLevel(levelDBus);
         server->activate();
 
@@ -225,13 +213,13 @@ int main(int argc, char **argv, char **envp)
 #endif
         server.reset();
         obj.reset();
-        guard.reset();
         SE_LOG_DEBUG(NULL, "flushing D-Bus connection");
         conn.flush();
         conn.reset();
         SE_LOG_INFO(NULL, "terminating, closing logging");
         syslogger.reset();
         redirect.reset();
+        guard.reset();
         SE_LOG_INFO(NULL, "terminating");
         return 0;
     } catch ( const std::exception &ex ) {
index a4d9cdc..135142e 100755 (executable)
 
 import dbus
 import dbus.service
-import gobject
+try:
+    import gobject
+except ImportError:
+    from gi.repository import GObject as gobject
 from dbus.mainloop.glib import DBusGMainLoop
 import functools
 import subprocess
index 40cab7f..9ee4a63 100755 (executable)
 
 import dbus
 import dbus.service
-import gobject
+try:
+    import gobject
+except ImportError:
+    from gi.repository import GObject as gobject
 from dbus.mainloop.glib import DBusGMainLoop
 import functools
 import sys
index 3b652fe..0d4de0a 100644 (file)
@@ -1291,7 +1291,7 @@ void Manager::doSetPeer(const boost::shared_ptr<Session> &session,
             // Local sync with files on the target side.
             // Format is hard-coded to vCard 3.0.
             source->setDatabaseID("file://" + address);
-            source->setDatabaseFormat("text/vcard");
+            source->setDatabaseFormat("raw/text/vcard");
             source->setBackend("file");
         }
         config->flush();
index 66da5af..fd469e0 100755 (executable)
@@ -815,7 +815,9 @@ XDG root.
         self.manager.Start()
         self.assertEqual("last/first", self.manager.GetSortOrder())
 
-    @timeout(os.environ.get('TESTPIM_TEST_SYNC_TESTCASES', False) and 300000 or 300)
+    @timeout(os.environ.get('TESTPIM_TEST_SYNC_TESTCASES', False) and 300000 or
+             usingValgrind() and 3000 or
+             300)
     @property("snapshot", "simple-sort")
     def testSync(self):
         '''TestContacts.testSync - test caching of a dummy peer which uses a real phone or a local directory as fallback'''
index 62628e5..8ecfe64 100644 (file)
@@ -144,6 +144,11 @@ if COND_DBUS_PIM
 src_dbus_server_service_files_in += \
   src/dbus/server/pim/org._01.pim.contacts.service.in
 
+test_SCRIPTS += \
+       src/dbus/server/pim/examples/search.py \
+       src/dbus/server/pim/examples/sync.py \
+       $(NOP)
+
 if ENABLE_TESTING
 test_SCRIPTS += \
        src/dbus/server/pim/testpim.py \
index 94cddfd..a3d1135 100644 (file)
@@ -345,7 +345,6 @@ void Server::getSessions(std::vector<DBusObject_t> &sessions)
 }
 
 Server::Server(GMainLoop *loop,
-               bool &shutdownRequested,
                boost::shared_ptr<Restart> &restart,
                const DBusConnectionPtr &conn,
                int duration) :
@@ -354,7 +353,8 @@ Server::Server(GMainLoop *loop,
                      SessionCommon::SERVER_IFACE,
                      boost::bind(&Server::autoTermCallback, this)),
     m_loop(loop),
-    m_shutdownRequested(shutdownRequested),
+    m_suspendFlagsSource(0),
+    m_shutdownRequested(false),
     m_restart(restart),
     m_conn(conn),
     m_lastSession(time(NULL)),
@@ -411,8 +411,31 @@ Server::Server(GMainLoop *loop,
     m_configChangedSignal.connect(boost::bind(boost::ref(configChanged)));
 }
 
+gboolean Server::onSuspendFlagsChange(GIOChannel *source,
+                                      GIOCondition condition,
+                                      gpointer data) throw ()
+{
+    Server *me = static_cast<Server *>(data);
+    try {
+        if (!SuspendFlags::getSuspendFlags().isNormal()) {
+            me->m_shutdownRequested = true;
+            g_main_loop_quit(me->m_loop);
+            SE_LOG_INFO(NULL, "server shutting down because of SIGINT or SIGTERM");
+        }
+    } catch (...) {
+        Exception::handle();
+    }
+    // Keep watching, just in case that we catch multiple signals.
+    return TRUE;
+}
+
 void Server::activate()
 {
+    // Watch SuspendFlags fd to react to signals quickly.
+    int fd = SuspendFlags::getSuspendFlags().getEventFD();
+    GIOChannelCXX channel(g_io_channel_unix_new(fd), TRANSFER_REF);
+    m_suspendFlagsSource = g_io_add_watch(channel, G_IO_IN, onSuspendFlagsChange, this);
+
     // Activate our D-Bus object *before* interacting with D-Bus
     // any further. Otherwise GIO D-Bus will start processing
     // messages for us while we start up and reject them because
@@ -446,6 +469,9 @@ void Server::activate()
 Server::~Server()
 {
     // make sure all other objects are gone before destructing ourselves
+    if (m_suspendFlagsSource) {
+        g_source_remove(m_suspendFlagsSource);
+    }
     m_syncSession.reset();
     m_workQueue.clear();
     m_clients.clear();
index 37e3f8c..0b22591 100644 (file)
@@ -64,7 +64,8 @@ class ServerLogger;
 class Server : public GDBusCXX::DBusObjectHelper
 {
     GMainLoop *m_loop;
-    bool &m_shutdownRequested;
+    guint m_suspendFlagsSource;
+    bool m_shutdownRequested;
     Timespec m_lastFileMod;
     boost::shared_ptr<SyncEvo::Restart> &m_restart;
     GDBusCXX::DBusConnectionPtr m_conn;
@@ -417,9 +418,13 @@ class Server : public GDBusCXX::DBusObjectHelper
     /** hooked into m_idleSignal, controls auto-termination */
     void onIdleChange(bool idle);
 
+    /** hooked up to SuspendFlags fd via g_io_add_watch */
+    static gboolean onSuspendFlagsChange(GIOChannel *source,
+                                         GIOCondition condition,
+                                         gpointer data) throw ();
+
 public:
     Server(GMainLoop *loop,
-           bool &shutdownRequested,
            boost::shared_ptr<Restart> &restart,
            const GDBusCXX::DBusConnectionPtr &conn,
            int duration);
index a313026..fe15b90 100644 (file)
@@ -317,6 +317,7 @@ SE_GOBJECT_TYPE(GFileMonitor)
 SE_GLIB_TYPE(GMainLoop, g_main_loop)
 SE_GLIB_TYPE(GAsyncQueue, g_async_queue)
 SE_GLIB_TYPE(GHashTable, g_hash_table)
+SE_GLIB_TYPE(GIOChannel, g_io_channel)
 
 SE_BEGIN_CXX
 
index 4a000a7..15301d8 100644 (file)
@@ -42,7 +42,7 @@ GVariantCXX HashTable2Variant(const GHashTable *hashTable) throw ()
     while (g_hash_table_iter_next(&iter, (gpointer *)&key, (gpointer *)&value)) {
         g_variant_builder_add(&builder, "{sv}", key, g_variant_ref(value));
     }
-    GVariantStealCXX variant(g_variant_builder_end(&builder));
+    GVariantStealCXX variant(g_variant_ref_sink(g_variant_builder_end(&builder)));
     return variant;
 }
 
index 88abfde..9b1bc2e 100644 (file)
@@ -2949,17 +2949,26 @@ void SyncContext::getConfigXML(bool isSync, string &xml, string &configname)
     substTag(xml, "maxobjsize", getMaxObjSize().get());
     if (m_serverMode) {
         UserIdentity id = getSyncUser();
-        Credentials cred = IdentityProviderCredentials(id, getSyncPassword());
-        const string &user = cred.m_username;
-        const string &password = cred.m_password;
 
         /*
          * Do not check username/pwd if this local sync or over
-         * bluetooth transport. Need credentials for checking.
+         * bluetooth transport. Need credentials for checking,
+         * and IdentityProviderCredentials() throws an error when
+         * called for a provider which does not support plain
+         * credentials.
          */
-        if (!m_localSync &&
-            !boost::starts_with(getUsedSyncURL(), "obex-bt") &&
-            (!user.empty() || !password.empty())) {
+        bool withauth = !m_localSync && !boost::starts_with(getUsedSyncURL(), "obex-bt");
+        if (withauth) {
+            Credentials cred = IdentityProviderCredentials(id, getSyncPassword());
+            const string &user = cred.m_username;
+            const string &password = cred.m_password;
+
+            if (user.empty() && password.empty()) {
+                withauth = false;
+            }
+        }
+
+        if (withauth) {
             // require authentication with the configured password
             substTag(xml, "defaultauth",
                      "<requestedauth>md5</requestedauth>\n"
@@ -2967,6 +2976,11 @@ void SyncContext::getConfigXML(bool isSync, string &xml, string &configname)
                      "<autononce>yes</autononce>\n",
                      true);
         } else {
+            if (id.wasSet()) {
+                SE_LOG_WARNING(getConfigName(), "ignoring username %s, it is not needed",
+                               id.toString().c_str());
+            }
+
             // no authentication required
             substTag(xml, "defaultauth",
                      "<logininitscript>return TRUE</logininitscript>\n"
diff --git a/src/syncevo/configs/scripting/00looptimeout.xml b/src/syncevo/configs/scripting/00looptimeout.xml
new file mode 100644 (file)
index 0000000..62809ac
--- /dev/null
@@ -0,0 +1,2 @@
+<!-- disable endless loop prevention, shouldn't be needed and may abort prematurely -->
+<looptimeout>0</looptimeout>
index da94383..1a1183e 100644 (file)
@@ -14,6 +14,9 @@
      winningchanged = 0;
      loosingchanged = 0;
 
+     STRING ignorefields;
+     ignorefields = "";
+
      if (SESSIONVAR("keepPhotoData") &&
          WINNING.PHOTO == EMPTY &&
          LOOSING.PHOTO != EMPTY) {
        LOOSING.PHOTO = EMPTY;
      }
 
+     // In cache mode, we don't care about the order of entries, so
+     // we do our own relaxed comparison and tell the engine to ignore
+     // fields if the only change is in the ordering.
+     if (CACHEDATA()) {
+       ignorefields = ignorefields + RELAXEDCOMPARE("TEL", "", "TEL_FLAGS", "TEL_SLOT", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("XDATE", "", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("EMAIL", "", "EMAIL_FLAGS", "EMAIL_SLOT", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("WEB", "", "WEB_FLAGS", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("CALURI");
+       ignorefields = ignorefields + RELAXEDCOMPARE("FBURL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("BLOGURL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("VIDEOURL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("RELATEDNAMES", "", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("IMPP", "", "IMPP_SERVICE", "IMPP_SLOT", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("AIM_HANDLE", "", "AIM_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("GADUGADU_HANDLE", "", "GADUGADU_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("GROUPWISE_HANDLE", "", "GROUPWISE_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("ICQ_HANDLE", "", "ICQ_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("JABBER_HANDLE", "", "JABBER_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("MSN_HANDLE", "", "MSN_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("YAHOO_HANDLE", "", "YAHOO_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("SKYPE_HANDLE", "", "SKYPE_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("SIP_HANDLE", "", "SIP_SLOT");
+       ignorefields = ignorefields + RELAXEDCOMPARE("EMAIL", "", "EMAIL_FLAGS", "EMAIL_SLOT", "LABEL");
+       ignorefields = ignorefields + RELAXEDCOMPARE("ADR", "ADR_STREET", "ADR_ADDTL", "ADR_STREET_FLAGS", "ADR_POBOX", "ADR_CITY", "ADR_REG", "ADR_ZIP", "ADR_COUNTRY", "", "LABEL");
+
+       // Always ignore the label. Otherwise reordering will cause unnecessary
+       // writes. We check for reordering more selectively above, but because
+       // the LABEL field is shared, we cannot do the same for it.
+       // The downside is that changes in just the label of an entry will not
+       // cause an update of the cache. Some other value must be modified, too,
+       // to trigger a write.
+       ignorefields = ignorefields + " LABEL";
+     }
+
      // When running in caching mode, we end up executing the merge script,
      // but in that case we want to remove data from the loosing item and
      // thus need to skip the array merging.
           i = i - 1;
        }
 
-       i = SIZE(LOOSING.WEB) - 1;
-       while (i >= 0) {
-          val = LOOSING.WEB[i];
-          if (val != EMPTY &&
-              !CONTAINS(WINNING.WEB, val)) {
-             num = SIZE(WINNING.LABEL);
-             WINNING.WEB[num] = val;
-             WINNING.WEB_FLAGS[num] = LOOSING.WEB_FLAGS[i];
-             WINNING.LABEL[num] = LOOSING.LABEL[i];
-             winningchanged = 1;
-          }
-          i = i - 1;
-       }
-
-       i = SIZE(LOOSING.WEB) - 1;
-       while (i >= 0) {
-          val = LOOSING.WEB[i];
-          if (val != EMPTY &&
-              !CONTAINS(WINNING.WEB, val)) {
-             num = SIZE(WINNING.LABEL);
-             WINNING.WEB[num] = val;
-             WINNING.WEB_FLAGS[num] = LOOSING.WEB_FLAGS[i];
-             WINNING.LABEL[num] = LOOSING.LABEL[i];
-             winningchanged = 1;
-          }
-          i = i - 1;
-       }
-
        i = SIZE(LOOSING.CALURI) - 1;
        while (i >= 0) {
           val = LOOSING.CALURI[i];
           i = i - 1;
        }
 
-       i = SIZE(LOOSING.CALURI) - 1;
-       while (i >= 0) {
-          val = LOOSING.CALURI[i];
-          if (val != EMPTY &&
-              !CONTAINS(WINNING.CALURI, val)) {
-             num = SIZE(WINNING.CALURI);
-             WINNING.CALURI[num] = val;
-             winningchanged = 1;
-          }
-          i = i - 1;
-       }
-
        i = SIZE(LOOSING.RELATEDNAMES) - 1;
        while (i >= 0) {
           val = LOOSING.RELATEDNAMES[i];
      if (loosingchanged) { SETLOOSINGCHANGED(1); }
 
      // Continue merge.
-     MERGEFIELDS(mode);
+     MERGEFIELDS(mode, ignorefields);
    ]]></macro>
diff --git a/src/syncevo/configs/scripting/client/00timeout.xml b/src/syncevo/configs/scripting/client/00timeout.xml
deleted file mode 100644 (file)
index c56df74..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-    <looptimeout>5</looptimeout>
-
index b14c18f..3cdbb1f 100644 (file)
@@ -1,6 +1,27 @@
 # Generated by configure.  Do not edit.
-# git revision 3b70881c62ee1909781dec57ac7dad781a0379fd
-# git tag libsynthesis_3.4.0.47+syncevolution-1-4-99-4
+# git revision f9202de6af47a44a227106e7a76f46cdeb1a6d53
+# git tag libsynthesis_3.4.0.47+syncevolution-1-5
+
+2014-10-30  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * configure.in:
+
+       autotools: bump Linux/SyncEvolution sub-version for
+       RELAXEDCOMPARE()
+
+2014-10-17  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/sysync/multifielditemtype.cpp:
+
+       merge script: check order of entries in RELAXEDCOMPARE()
+
+2014-10-09  Patrick Ohly  <patrick.ohly@intel.com>
+
+       * src/sysync/multifielditem.cpp:
+       * src/sysync/multifielditem.h:
+       * src/sysync/multifielditemtype.cpp:
+
+       merge scripts: new RELAXEDCOMPARE(), enhanced MERGEFIELDS()
 
 2014-09-10  Patrick Ohly  <patrick.ohly@intel.com>
 
index b1ade1b..9912dcb 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.65 for synthesis 3.4.0.47.4.
+# Generated by GNU Autoconf 2.65 for synthesis 3.4.0.47.5.
 #
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -698,8 +698,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='synthesis'
 PACKAGE_TARNAME='synthesis'
-PACKAGE_VERSION='3.4.0.47.4'
-PACKAGE_STRING='synthesis 3.4.0.47.4'
+PACKAGE_VERSION='3.4.0.47.5'
+PACKAGE_STRING='synthesis 3.4.0.47.5'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1465,7 +1465,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 synthesis 3.4.0.47.4 to adapt to many kinds of systems.
+\`configure' configures synthesis 3.4.0.47.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1535,7 +1535,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of synthesis 3.4.0.47.4:";;
+     short | recursive ) echo "Configuration of synthesis 3.4.0.47.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1689,7 +1689,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-synthesis configure 3.4.0.47.4
+synthesis configure 3.4.0.47.5
 generated by GNU Autoconf 2.65
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2175,7 +2175,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 synthesis $as_me 3.4.0.47.4, which was
+It was created by synthesis $as_me 3.4.0.47.5, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   $ $0 $@
@@ -2983,7 +2983,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='synthesis'
- VERSION='3.4.0.47.4'
+ VERSION='3.4.0.47.5'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -16058,7 +16058,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 synthesis $as_me 3.4.0.47.4, which was
+This file was extended by synthesis $as_me 3.4.0.47.5, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -16124,7 +16124,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="\\
-synthesis config.status 3.4.0.47.4
+synthesis config.status 3.4.0.47.5
 configured by $0, generated by GNU Autoconf 2.65,
   with options \\"\$ac_cs_config\\"
 
index c5fea66..fc459ab 100644 (file)
@@ -2,7 +2,7 @@ dnl Invoke autogen.sh to produce a configure script.
 
 # four digit upstream version, one additional digit for
 # Linux/SyncEvolution specific extensions:
-AC_INIT([synthesis], [3.4.0.47.4])
+AC_INIT([synthesis], [3.4.0.47.5])
 AM_INIT_AUTOMAKE(subdir-objects)
 AC_CONFIG_MACRO_DIR([m4])
 AM_CONFIG_HEADER(config.h)
index c933fae..49e6a8f 100755 (executable)
@@ -1381,10 +1381,15 @@ void TMultiFieldItem::mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aCha
 // returns update status of this and other item. Note that changes of non-relevant fields are
 // not reported here.
 void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther,
-                                        int mode)
+                                        int mode,
+                                        const std::set<std::string> &aIgnoreFields)
 {
   // same type of multifield, try to merge
   for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
+    // Ignore fields if told so by optional MERGEFIELDS() parameter.
+    if (aIgnoreFields.find(fFieldDefinitionsP->fFields[i].fieldname) != aIgnoreFields.end()) {
+      continue;
+    }
     // get merge mode
     sInt16 sep=fFieldDefinitionsP->fFields[i].mergeMode;
     // possible merging is only relevant (=to be reported) for fields that are not eqm_none
index 0cc14bd..5359c4c 100755 (executable)
@@ -20,7 +20,7 @@
 #include "configelement.h"
 #include "syncappbase.h"
 
-
+#include <set>
 
 using namespace sysync;
 
@@ -327,7 +327,7 @@ public:
   // Note that changes of non-relevant fields are not reported here.
   virtual void mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS *aDatastoreP, int mode = MERGE_OPTION_FROM_CONFIG);
   // standard merge (subset of mergeWith, used if no merge script is defined)
-  void standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther, int mode = MERGE_OPTION_FROM_CONFIG);
+  void standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther, int mode = MERGE_OPTION_FROM_CONFIG, const std::set<std::string> &aIgnoreFields = std::set<std::string>());
   // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
   // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
   virtual sInt16 compareWith(
index a26fe54..3d89c1f 100755 (executable)
@@ -189,19 +189,164 @@ public:
   }; // func_IgnoreUpdate
 
 
-  // void MERGEFIELDS(mode = 0)
+  // void MERGEFIELDS(mode = 0, ignoreFields = "")
   // Optional mode parameter determines the result of the merge.
   // 0 = according to config, 1 = loosing item is overwritten, 2 = winning item is overwritten
+  // Any field names in the space separated ignoreFields parameter will be skipped.
+  // The assumption is that the calling script has already dealt with these fields.
   static void func_MergeFields(TItemField *&aTermP, TScriptContext *aFuncContextP)
   {
     TMultiFieldItemType *mfitP = static_cast<TMultiFieldItemType *>(aFuncContextP->getCallerContext());
     if (mfitP->fFirstItemP) {
       TItemField *argP = aFuncContextP->getLocalVar(0);
+      int mode = (argP && argP->isAssigned()) ? argP->getAsInteger() : 0;
+      // Split optional string into set of field names.
+      argP = aFuncContextP->getLocalVar(1);
+      std::string fields;
+      if (argP && argP->isAssigned()) {
+        argP->getAsString(fields);
+      }
+      std::set<std::string> ignoreFields;
+      size_t offset = 0;
+      while (offset < fields.size()) {
+        while (offset < fields.size() && isspace(fields[offset])) offset++;
+        size_t start = offset;
+        while (offset < fields.size() && !isspace(fields[offset])) offset++;
+        size_t len = offset - start;
+        if (len)
+          ignoreFields.insert(fields.substr(start, len));
+      }
       mfitP->fFirstItemP->standardMergeWith(*(mfitP->fSecondItemP),mfitP->fChangedFirst,mfitP->fChangedSecond,
-                                            (argP && argP->isAssigned()) ? argP->getAsInteger() : 0);
+                                            mode, ignoreFields);
     }
   }; // func_MergeFields
 
+  enum ArrayEntriesState {
+    ALL_UNSET, // All arrays have no entries at the array index -> past end of valid entries.
+    ALL_EMPTY, // Some entries exist, but all of those are empty.
+    NON_EMPTY  // Some entry is non-empty.
+  };
+  static ArrayEntriesState checkArrayEntries(sInt16 arridx, TMultiFieldItem &aItem, const std::vector<sInt16> &aFields)
+  {
+    ArrayEntriesState state = ALL_UNSET;
+    for (size_t i = 0; state != NON_EMPTY && i < aFields.size() && aFields[i] >= 0; i++) {
+      TItemField *elemP = aItem.getArrayField(aFields[i],arridx,true);
+      if (elemP && state == ALL_UNSET) {
+        state = elemP->isEmpty() ? ALL_EMPTY : NON_EMPTY;
+      }
+    }
+    return state;
+  }
+
+  // Increments arridx until it runs into ALL_UNSET or NON_EMPTY.
+  static ArrayEntriesState nextArrayEntries(sInt16 &arridx, TMultiFieldItem &aItem, const std::vector<sInt16> &aFields)
+  {
+    while (true) {
+      ++arridx;
+      ArrayEntriesState state = checkArrayEntries(arridx, aItem, aFields);
+      switch (state) {
+      case ALL_UNSET:
+      case NON_EMPTY:
+        return state;
+      case ALL_EMPTY:
+        break;
+      }
+    }
+  }
+
+  // string RELAXEDCOMPARE(mainfield1, mainfield2, mainfield3, "", addfield1, addfield2, ...)
+  // Returns "" if a relaxed comparison of the given fields in the winning and loosing
+  // item finds no differences and string with all given field names concatenated together
+  // with space at the beginning and and the end.
+  //
+  // The intended usage is:
+  // ignorefields = ignorefields + RELAXEDCOMPARE("TEL", "", "TEL_FLAGS", "LABEL");
+  // ignorefields = ignorefields + RELAXEDCOMPARE("ADR", "ADR_STREET", "ADR_CITY", "", "LABEL");
+  // MERGEFIELDS(mode, ignorefields);
+  //
+  // All fields must be arrays. Only entries with non-empty main fields are considered.
+  // However, if the main fields are non-empty, the additional ones must also match.
+  // The order of entries in loosing and winning item *does* matter, a difference
+  // is only reported if an entry has no exact match in the other item.
+  static void func_RelaxedCompare(TItemField *&aTermP, TScriptContext *aFuncContextP)
+  {
+    TMultiFieldItemType *mfitP = static_cast<TMultiFieldItemType *>(aFuncContextP->getCallerContext());
+    bool difference = false;
+    std::string fieldnames;
+    if (mfitP->fFirstItemP && mfitP->fSecondItemP) {
+      // Determine field index of the fields we need to compare.
+      std::vector<sInt16> fields;
+      TFieldListConfig *fieldlist = mfitP->fFirstItemP->getFieldDefinitions();
+      for (int i = 0; ; i++) {
+        TItemField *argP = aFuncContextP->getLocalVar(i);
+        if (!argP || !argP->isAssigned()) {
+          break;
+        }
+        std::string fieldname;
+        argP->getAsString(fieldname);
+        if (fieldname.empty()) {
+          // Separator between main and additional fields.
+          fields.push_back(-1);
+        } else {
+          for (sInt16 e=0; e<fieldlist->numFields(); e++) {
+            if (fieldlist->fFields[e].fieldname == fieldname) {
+              fieldnames.append(" ");
+              fieldnames.append(fieldname);
+              fields.push_back(e);
+              break;
+            }
+          }
+          // TODO (?): error for unknown field
+        }
+      }
+
+      if (!fields.empty()) {
+        // Walk through both array sets in parallel. Skip empty
+        // entries and compare non-empty ones.
+        sInt16 firstArrIdx = -1;
+        ArrayEntriesState firstState = nextArrayEntries(firstArrIdx, *mfitP->fFirstItemP, fields);
+        sInt16 secondArrIdx = -1;
+        ArrayEntriesState secondState = nextArrayEntries(secondArrIdx, *mfitP->fSecondItemP, fields);
+
+        while (firstState == NON_EMPTY &&
+               secondState == NON_EMPTY) {
+          // Compare entries.
+          for (size_t i=0; i<fields.size(); i++) {
+            sInt16 fid = fields[i];
+            if (fid == -1) {
+              continue;
+            }
+            TItemField *firstP = mfitP->fFirstItemP->getArrayField(fid, firstArrIdx, true);
+            TItemField *secondP = mfitP->fSecondItemP->getArrayField(fid, secondArrIdx, true);
+            if (firstP && secondP) {
+              if (firstP->isAssigned() != secondP->isAssigned() ||
+                  *firstP != *secondP) {
+                difference = true;
+                break;
+              }
+            } else if ((firstP && firstP->isAssigned()) ||
+                       (secondP && secondP->isAssigned())) {
+              difference = true;
+              break;
+            }
+          }
+          firstState = nextArrayEntries(firstArrIdx, *mfitP->fFirstItemP, fields);
+          secondState = nextArrayEntries(secondArrIdx, *mfitP->fSecondItemP, fields);
+        }
+
+        if (firstState != secondState) {
+          // One side has data that the other hasn't.
+          difference = true;
+        }
+      } else {
+        // TODO (?): error if no fields specified.
+      }
+    } else {
+      difference = true;
+    }
+
+    aTermP->setAsString(difference ? "" : fieldnames);
+  }; // func_RelaxedCompare
 
   // integer WINNINGCHANGED()
   // returns true if winning was changed
@@ -355,6 +500,8 @@ static void* DataTypeChainFunc(void *&aNextCallerContext)
 
 const uInt8 param_StrArg[] = { VAL(fty_string) };
 const uInt8 param_IntArg[] = { VAL(fty_integer) };
+const uInt8 param_RelaxedCompare[] = { OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string), OPTVAL(fty_string),};
+const uInt8 param_MergeFields[] = { OPTVAL(fty_integer), OPTVAL(fty_string) };
 
 // builtin functions for datastore-context table
 const TBuiltInFuncDef DataTypeFuncDefs[] = {
@@ -371,7 +518,8 @@ const TBuiltInFuncDef DataTypeFuncDefs[] = {
   { "DELETEWINS", TMFTypeFuncs::func_DeleteWins, fty_none, 0, NULL },
   { "PREVENTADD", TMFTypeFuncs::func_PreventAdd, fty_none, 0, NULL },
   { "IGNOREUPDATE", TMFTypeFuncs::func_IgnoreUpdate, fty_none, 0, NULL },
-  { "MERGEFIELDS", TMFTypeFuncs::func_MergeFields, fty_none, 1, param_oneOptInteger },
+  { "MERGEFIELDS", TMFTypeFuncs::func_MergeFields, fty_none, sizeof(param_MergeFields)/sizeof(param_MergeFields[0]), param_MergeFields },
+  { "RELAXEDCOMPARE", TMFTypeFuncs::func_RelaxedCompare, fty_string, sizeof(param_RelaxedCompare)/sizeof(param_RelaxedCompare[0]), param_RelaxedCompare },
   { "WINNINGCHANGED", TMFTypeFuncs::func_WinningChanged, fty_integer, 0, NULL },
   { "LOOSINGCHANGED", TMFTypeFuncs::func_LoosingChanged, fty_integer, 0, NULL },
   { "SETWINNINGCHANGED", TMFTypeFuncs::func_SetWinningChanged, fty_none, 1, param_IntArg },
diff --git a/src/testcases/eds_contact.vcf.filekde.tem b/src/testcases/eds_contact.vcf.filekde.tem
new file mode 100644 (file)
index 0000000..85e04c5
--- /dev/null
@@ -0,0 +1,356 @@
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user17\r
+NICKNAME:user17\r
+NOTE:triggers parser bug in Funambol 3.0: trailing = is mistaken for soft line break=\r
+FN:parserbug=\r
+N:parserbug=;;;;\r
+X-EVOLUTION-FILE-AS:parserbug=\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user16\r
+NICKNAME:user16\r
+NOTE:test case with empty email\r
+FN:incomplete\r
+N:incomplete;;;;\r
+EMAIL:\r
+X-EVOLUTION-FILE-AS:incomplete\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user11\r
+NICKNAME:user11\r
+NOTE:This is a long line without any special characters. This is a simpler \r
+ example that should require folding in vcards. Does folding insert a crlf\r
+  before a space or does it insert crlf _plus_ a space? vCard 2.1 inserts \r
+ before a space\, 3.0 inserts line break plus space.\r
+FN:long line\r
+N:line;long;;;\r
+X-EVOLUTION-FILE-AS:line\, long\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user13\r
+NICKNAME:user13\r
+NOTE:a colon is not a special character so here it comes : and not quoting necessary\r
+FN:colon\r
+N:colon;unquoted;;;\r
+X-EVOLUTION-FILE-AS:colon\, unquoted\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user14\r
+NICKNAME:user14\r
+NOTE:here are some quotation marks: single ' double " back ` - none of them is special\r
+FN:quotation marks\r
+N:marks;quotation;;;\r
+X-EVOLUTION-FILE-AS:marks\, quotation\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user15\r
+NICKNAME:user15\r
+NOTE:Spouse's Name: foobar\r
+FN:spouse name\r
+N:name;spouse;;;\r
+X-EVOLUTION-FILE-AS:spouse\, name\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user9\r
+NICKNAME:user9\r
+NOTE;CHARSET="UTF-8":Tests charset specification with quotation marks.\r
+FN:charset\r
+N:set;char;;;\r
+X-EVOLUTION-FILE-AS:set\, char\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+URL:\r
+TITLE:\r
+ROLE:\r
+X-EVOLUTION-MANAGER:\r
+X-EVOLUTION-ASSISTANT:\r
+UID:unique-id-user7\r
+NICKNAME:user7\r
+X-EVOLUTION-SPOUSE:\r
+NOTE:This test case uses line breaks. This is line 1.\nLine 2.\n\nLine brea\r
+ ks in vcard 2.1 are encoded as =0D=0A.\nThat means the = has to be encod\r
+ ed itself...\r
+FN:line breaks\r
+N:breaks;line;;;\r
+X-EVOLUTION-FILE-AS:breaks\, line\r
+X-EVOLUTION-BLOG-URL:\r
+CALURI:\r
+FBURL:\r
+X-EVOLUTION-VIDEO-URL:\r
+X-MOZILLA-HTML:FALSE\r
+ADR;TYPE=HOME:;Address Line 2\nAddress Line 3;Address Line 1;;;;\r
+LABEL;TYPE=HOME:Address Line 1\nAddress Line 2\nAddress Line 3\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+URL:http://john.doe.com\r
+TITLE:Senior Tester\r
+ORG:Test Inc.;Testing;test#1\r
+ROLE:professional test case\r
+X-EVOLUTION-MANAGER:John Doe Senior\r
+X-EVOLUTION-ASSISTANT:John Doe Junior\r
+UID:unique-id-user1\r
+NICKNAME:user1\r
+BDAY:2006-01-08\r
+X-EVOLUTION-ANNIVERSARY:2006-01-09\r
+X-EVOLUTION-SPOUSE:Joan Doe\r
+NOTE:This is a test case which uses almost all Evolution fields.\r
+FN:John Doe\r
+N:Doe;John;;;\r
+X-EVOLUTION-FILE-AS:Doe\, John\r
+CATEGORIES:TEST\r
+X-EVOLUTION-BLOG-URL:web log\r
+GEO:30.12;-130.34\r
+X-EVOLUTION-VIDEO-URL:chat\r
+X-MOZILLA-HTML:TRUE\r
+ADR;TYPE=WORK:Test Box #2;;Test Drive 2;Test Town;Upper Test County;12346;O\r
+ ld Testovia\r
+LABEL;TYPE=WORK:Test Drive 2\nTest Town\, Upper Test County\n12346\nTest Bo\r
+ x #2\nOld Testovia\r
+ADR;TYPE=HOME:Test Box #1;;Test Drive 1;Test Village;Lower Test County;1234\r
+ 5;Testovia\r
+LABEL;TYPE=HOME:Test Drive 1\nTest Village\, Lower Test County\n12345\nTest\r
+  Box #1\nTestovia\r
+ADR:Test Box #3;;Test Drive 3;Test Megacity;Test County;12347;New Testonia\r
+LABEL;TYPE=OTHER:Test Drive 3\nTest Megacity\, Test County\n12347\nTest Box\r
+  #3\nNew Testonia\r
+EMAIL:john.doe@work.com\r
+EMAIL:john.doe@home.priv\r
+EMAIL:john.doe@other.world\r
+EMAIL:john.doe@yet.another.world\r
+TEL;TYPE=work;TYPE=Voice;X-EVOLUTION-UI-SLOT=1:business 1\r
+TEL;TYPE=homE;TYPE=VOICE;X-EVOLUTION-UI-SLOT=2:home 2\r
+TEL;TYPE=CELL;X-EVOLUTION-UI-SLOT=3:mobile 3\r
+TEL;TYPE=WORK;TYPE=FAX;X-EVOLUTION-UI-SLOT=4:businessfax 4\r
+TEL;TYPE=HOME;TYPE=FAX;X-EVOLUTION-UI-SLOT=5:homefax 5\r
+TEL;TYPE=PAGER;X-EVOLUTION-UI-SLOT=6:pager 6\r
+TEL;TYPE=CAR;X-EVOLUTION-UI-SLOT=7:car 7\r
+TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 8\r
+X-AIM;X-EVOLUTION-UI-SLOT=1:AIM JOHN\r
+X-YAHOO;X-EVOLUTION-UI-SLOT=2:YAHOO JDOE\r
+X-ICQ;X-EVOLUTION-UI-SLOT=3:ICQ JD\r
+X-GROUPWISE;X-EVOLUTION-UI-SLOT=4:GROUPWISE DOE\r
+X-GADUGADU:GADUGADU DOE\r
+X-JABBER:JABBER DOE\r
+X-MSN:MSN DOE\r
+X-SKYPE:SKYPE DOE\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+URL:\r
+TITLE:\r
+ROLE:\r
+X-EVOLUTION-MANAGER:\r
+X-EVOLUTION-ASSISTANT:\r
+UID:unique-id-user5\r
+NICKNAME:user5\r
+X-EVOLUTION-SPOUSE:\r
+NOTE:image in JPG format\r
+FN:Ms. JPG\r
+N:;JPG;;Ms.;\r
+X-EVOLUTION-FILE-AS:JPG\r
+X-EVOLUTION-BLOG-URL:\r
+CALURI:\r
+FBURL:\r
+X-EVOLUTION-VIDEO-URL:\r
+X-MOZILLA-HTML:FALSE\r
+PHOTO;ENCODING=b;TYPE=JPEG:/9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAA\r
+ AAgAAAAAAAD//gAXQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAFAwQEBAMFBAQEBQUFBgcM\r
+ CAcHBwcPCwsJDBEPEhIRDxERExYcFxMUGhURERghGBodHR8fHxMXIiQiHiQcHh8e/9sAQwEF\r
+ BQUHBgcOCAgOHhQRFB4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e\r
+ Hh4eHh4eHh4e/8AAEQgAFwAkAwEiAAIRAQMRAf/EABkAAQADAQEAAAAAAAAAAAAAAAAGBwgE\r
+ Bf/EADIQAAECBQMCAwQLAAAAAAAAAAECBAADBQYRBxIhEzEUFSIIFjNBGCRHUVZ3lqXD0+P/\r
+ xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMR\r
+ AD8AuX6UehP45/aXv9MTPTLVKxNSvMPcqu+a+XdLxf1SfJ6fU37PioTnOxfbOMc/KIZ7U/2V\r
+ fmTR/wCaKlu6+blu/Ui72zxWtUmmUOrTaWwkWDT09FPR4K587OVrUfVsIwElPPPAbAjxr2um\r
+ hWXbDu5rmfeApLPZ4hx0lzNm9aUJ9KAVHKlJHAPf7ozPLqWt9y6Z0EPGmoLNjTq48a1iaybJ\r
+ YV52yEtCms5KJmAT61JXtJyUdyQTEc1WlMql7N1/oZ6jagVZVFfUyZPpFy5lvWcxU7Z03BUk\r
+ GZLWJqVhPYLkIIPBEBtSEUyNAsjI1q1m/VP+UICwL/sqlXp7v+aOHsnyGttq218MtKd8+Ru2\r
+ JXuScoO45Awe2CIi96aKW1cVyubkYVy6rTqz0J8a5t2qqZl0UjAMwYKScfPAJ+cIQHHP0Dth\r
+ VFaMWt0XwxetnM50Ks2rsxL6ZMnJlJmb5hBBBEiVxjA28dznqo+hdksbQuS3Hs6tVtNzdM1Z\r
+ /VH5nO3Bl/CJmYHKDynjv3zCEB5rLQNo0bIbydWNWxKljbLQLoWkISOAkBKAABCEID//2Q==\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+URL:\r
+TITLE:\r
+ROLE:\r
+X-EVOLUTION-MANAGER:\r
+X-EVOLUTION-ASSISTANT:\r
+UID:unique-id-user4\r
+NICKNAME:user4\r
+X-EVOLUTION-SPOUSE:\r
+NOTE:image in PNG format\r
+FN:Mrs. PNG\r
+N:;PNG;;Mrs.;\r
+X-EVOLUTION-FILE-AS:PNG\r
+X-EVOLUTION-BLOG-URL:\r
+CALURI:\r
+FBURL:\r
+X-EVOLUTION-VIDEO-URL:\r
+X-MOZILLA-HTML:FALSE\r
+PHOTO;ENCODING=b;TYPE=PNG:iVBORw0KGgoAAAANSUhEUgAAACQAAAAXCAYAAABj7u2bAAAAB\r
+ mJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1gEICjgdiWkBO\r
+ QAAAB10RVh0Q29tbWVudABDcmVhdGVkIHdpdGggVGhlIEdJTVDvZCVuAAABaElEQVRIx+3Wu\r
+ 0tcURAG8F98gRKTYGORRqwksJV/QOqFFIFgKgsRYbHV1larDQQCKQxpUscyhUmXJuCSNpYWP\r
+ sAU6wPxHW6aWbgsu+ve3RUs7geHc+fON3O+M4c5HHLkyHG/eISkg5heIGmUr++hVWigyY6TH\r
+ lejbWSt0Bv8QBXX2MF7jKU4IyjjJ45xg31sYKZuw7Xv9Gh6vvXO9QbBtbGNJ8Ert+AlTURkF\r
+ jQX9g5e4ykGUcBm+FaDexx2MUQOYhIL2Lpj09oV9CvsQgPuePj+hP037BL6M6yRSdDZHWVOc\r
+ BHcEv7FvyN8xxqmeynovA1Baf4UVvANhyn/Uq8E/Q57ssNufhvx1QZrDHfS9p9i3sQsnscdN\r
+ owXWEQlOBXMYyI4j3EavqFUzpOYl4OTqUJ9+NzmkbXyb6Ryfumm7Wso4it2cYXL6K6PeBmcV\r
+ 8E5iEvxPDjv8CyVaxQfsIfbqGIlf17k6Bb/Ae0cnahfg6KuAAAAAElFTkSuQmCC\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+URL:\r
+TITLE:\r
+ROLE:\r
+X-EVOLUTION-MANAGER:\r
+X-EVOLUTION-ASSISTANT:\r
+UID:unique-id-user3\r
+NICKNAME:user3\r
+X-EVOLUTION-SPOUSE:\r
+NOTE:image in GIF format\r
+FN:Mr. GIF\r
+N:;GIF;;Mr.;\r
+X-EVOLUTION-FILE-AS:GIF\r
+X-EVOLUTION-BLOG-URL:\r
+CALURI:\r
+FBURL:\r
+X-EVOLUTION-VIDEO-URL:\r
+X-MOZILLA-HTML:FALSE\r
+PHOTO;ENCODING=b;TYPE=GIF:R0lGODlhJAAXAIABAAAAAP///yH+FUNyZWF0ZWQgd2l0aCBUa\r
+ GUgR0lNUAAh+QQBCgABACwAAAAAJAAXAAACVYyPqcvtD6OctNqLFdi8b/sd3giAJRNmqXaKH\r
+ TIaZJKSpx3McLtyeSuTAWm34e+4WBGFuJ/P1QjZek9ksjiRGqFCTW5pZblmzdiO+GJWncqM+\r
+ w2PwwsAOw==\r
+END:VCARD\r
+\r
+BEGIN:VCARD\r
+VERSION:3.0\r
+UID:unique-id-user10\r
+NICKNAME:user10\r
+X-EVOLUTION-SPOUSE:\r
+NOTE:large vcard with plenty of special chars < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+  & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & < & <\r
+FN:large vcard\r
+N:;vcard;;large;\r
+X-EVOLUTION-FILE-AS:large\r
+END:VCARD\r
index 3e0d00f..3e3e585 100644 (file)
@@ -3128,12 +3128,14 @@ void SyncTests::doCopy() {
     CT_ASSERT_NO_THROW(deleteAll());
     accessClientB->deleteAll();
 
+    bool allowLocalUpdate = getenv("CLIENT_TEST_MAY_COPY_BACK") != NULL;
+
     // insert into first database, copy to server
     CT_ASSERT_NO_THROW(allSourcesInsert());
     doSync(__FILE__, __LINE__,
            "send",
            SyncOptions(SYNC_TWO_WAY,
-                       CheckSyncReport(0,0,0, 1,0,0, true, SYNC_TWO_WAY)));
+                       CheckSyncReport(0, allowLocalUpdate? -1 : 0, 0, 1,0,0, true, SYNC_TWO_WAY)));
 
     // copy into second database
     accessClientB->doSync(__FILE__, __LINE__,
@@ -6042,9 +6044,11 @@ void SyncTests::testTimeout()
     close(fd);
     if (!skipped) {
         CT_ASSERT_EQUAL(STATUS_TRANSPORT_FAILURE, report.getStatus());
-        CT_ASSERT(end - start >= 19);
-        CT_ASSERT(end - start < 40); // needs to be sufficiently larger than 20s timeout
-                                     // because under valgrind the startup time is considerable
+        std::string delta = StringPrintf("%lds", (long)(end - start));
+        CT_ASSERT_MESSAGE(delta, end - start >= 19);
+        // needs to be sufficiently larger than 20s timeout
+        // because under valgrind the startup time is considerable
+        CT_ASSERT_MESSAGE(delta, end - start < 50);
     }
 }
 
index a794489..ec05f0b 100644 (file)
@@ -32,6 +32,7 @@
 #include <signal.h>
 #ifdef HAVE_VALGRIND_VALGRIND_H
 # include <valgrind/valgrind.h>
+# include <valgrind/memcheck.h>
 #endif
 #ifdef HAVE_EXECINFO_H
 # include <execinfo.h>
@@ -65,6 +66,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <fcntl.h>
 
 #include <string>
@@ -99,7 +101,9 @@ public:
     ClientOutputter(CppUnit::TestResultCollector *result, std::ostream &stream) :
         CompilerOutputter(result, stream) {}
     void write() {
-        CompilerOutputter::write();
+        // Suppress writing useless test summary. We run only one test per process,
+        // so this Outputter would not show the overall results.
+        // CompilerOutputter::write();
     }
 };
 
@@ -269,12 +273,48 @@ static void printTests(CppUnit::Test *test, int indention)
     }
 }
 
+static void addEnabledTests(CppUnit::Test *test, bool parentEnabled,
+                            char **beginEnabled, char **endEnabled,
+                            std::list<std::string> &result)
+{
+    if (!test) {
+        return;
+    }
+
+    std::string name = test->getName();
+    bool enabled = false;
+    if (parentEnabled) {
+        enabled = true;
+    } else {
+        for (char **selected = beginEnabled;
+             selected < endEnabled;
+             selected++) {
+            if (name == *selected) {
+                enabled = true;
+                break;
+            }
+        }
+    }
+
+    if (dynamic_cast<CppUnit::TestLeaf *>(test)) {
+        if (enabled) {
+            result.push_back(name);
+        }
+    } else {
+        for (int i = 0; i < test->getChildTestCount(); i++) {
+            addEnabledTests(test->getChildTestAt(i), enabled,
+                            beginEnabled, endEnabled,
+                            result);
+        }
+    }
+}
+
 static void handler(int sig)
 {
     void *buffer[100];
     int size;
 
-    fprintf(stderr, "\ncaught signal %d\n", sig);
+    fprintf(stderr, "client-test %ld: \ncaught signal %d\n", (long)getpid(), sig);
     fflush(stderr);
 #ifdef HAVE_EXECINFO_H
     size = backtrace(buffer, sizeof(buffer)/sizeof(buffer[0]));
@@ -338,20 +378,75 @@ int main(int argc, char* argv[])
   }
 
   try {
-      // Run the tests.
+      // Find all enabled tests.
+      std::list<std::string> tests;
       if (argc <= 1) {
-          // all tests
-          runner.run("", false, true, false);
+          // All tests.
+          addEnabledTests(suite, true, NULL, NULL, tests);
       } else {
-          // run selected tests individually
-          for (int test = 1; test < argc; test++) {
-              runner.run(argv[test], false, true, false);
+          // Some selected tests.
+          addEnabledTests(suite, false, argv + 1, argv + argc, tests);
+      }
+
+      bool failed = false;
+      if (tests.size() == 1) {
+          // If one test, run it ourselves.
+          runner.run(tests.front(), false, true, false);
+          failed = syncListener.hasFailed();
+      } else {
+          // Otherwise act as test runner which invokes itself
+          // recursively for each test. This way we keep running
+          // even if one test crashes hard, valgrind can check
+          // each test individually and uses less memory.
+          BOOST_FOREACH (const std::string &name, tests) {
+#ifdef USE_SYSTEM
+              if (system(StringPrintf("%s %s", argv[0], name.c_str()).c_str())) {
+                  failed = true;
+              }
+#else
+              // Avoid the intermediate shell process that system() uses and
+              // do better result reporting.
+              pid_t child = fork();
+              if (child > 0) {
+                  while (true) {
+                      int status;
+                      pid_t completed = waitpid(child, &status, 0);
+                      if (completed == -1) {
+                          perror("waitpid");
+                          failed = true;
+                      } else {
+                          if (WIFEXITED(status)) {
+                              int retcode = WEXITSTATUS(status);
+                              if (retcode != 0) {
+                                  printf("%s (%ld): failed with return code %d", name.c_str(), (long)child, retcode);
+                                  failed = true;
+                              }
+                          } else if (WIFSIGNALED(status)) {
+                              printf("%s (%ld): killed by signal %d", name.c_str(), (long)child, WTERMSIG(status));
+                              failed = true;
+                          }
+                          fflush(stdout);
+                          break;
+                      }
+                  }
+              } else if (child == -1) {
+                  perror("fork");
+              } else {
+                  // Use the test name also as name of the process.
+                  execlp(argv[0], name.c_str(), name.c_str(), (char *)NULL);
+                  perror("execlp");
+                  _exit(1);
+              }
+#endif
           }
       }
 
       // Return error code 1 if the one of test failed.
+      if (tests.size() > 1) {
+          printf("%s", failed ? "FAILED" : "OK");
+      }
       ClientTest::shutdown();
-      return syncListener.hasFailed() ? 1 : 0;
+      return failed;
   } catch (invalid_argument e) {
       // Test path not resolved
       std::cout << std::endl
index b944340..2afd4ea 100644 (file)
@@ -98,6 +98,7 @@ my $radicale = $server =~ /radicale/;
 my $zimbra = $server =~ /zimbra/;
 my $evolution = $client =~ /evolution/;
 my $addressbook = $client =~ /addressbook/;
+my $akonadi = $server =~ /kde/;
 
 sub Usage {
   print "$0 <vcards.vcf\n";
@@ -743,6 +744,15 @@ sub NormalizeItem {
         s/^(GEO)(;[^:;\n]*)*:.*\r?\n?//gm;
     }
 
+    if ($akonadi) {
+        # Akonadi adds empty GEO propery....
+        s/^(GEO)(;[^:;\n]*)*:0+\.0+;0+\.0+\r?\n?//gm;
+        # ... and rounds other values.
+        s/^(GEO(?:;[^:;\n]*)*):([-+]?\d+)\.\d+;([-+]?\d+)\.\d+/$1:$2;$3/gm;
+        # does not preserve X-EVOLUTION-UI-SLOT=
+        s/^(\w+)([^:\n]*);X-EVOLUTION-UI-SLOT=\d+/$1$2/mg;
+    }
+
     if ($googleeas || $exchange) {
         # temporarily ignore modified properties
         s/^(BDAY|X-ANNIVERSARY)(;[^:;\n]*)*:.*\r?\n?//gm;
index 6cae84e..34b76f6 100644 (file)
@@ -39,7 +39,7 @@ TEL;TYPE=WORK;TYPE=FAX:businessfax 4
 TEL;TYPE=HOME;TYPE=FAX:homefax 5
 TEL;TYPE=PAGER:pager 6
 TEL;TYPE=CAR:car 7
-TEL;TYPE=PREF:primary 80
+TEL;TYPE=PREF:primary 8xx
 X-AIM:AIM JOHN
 X-YAHOO:YAHOO JDOE
 X-ICQ:ICQ JD
@@ -127,7 +127,7 @@ TEL;TYPE=WORK;TYPE=FAX;X-EVOLUTION-UI-SLOT=4:businessfax 4
 TEL;TYPE=HOME;TYPE=FAX;X-EVOLUTION-UI-SLOT=5:homefax 5
 TEL;TYPE=PAGER;X-EVOLUTION-UI-SLOT=6:pager 6
 TEL;TYPE=CAR;X-EVOLUTION-UI-SLOT=7:car 7
-TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 80
+TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 8xx
 X-AIM;X-EVOLUTION-UI-SLOT=1:AIM JOHN
 X-YAHOO;X-EVOLUTION-UI-SLOT=2:YAHOO JDOE
 X-ICQ;X-EVOLUTION-UI-SLOT=3:ICQ JD
@@ -213,7 +213,7 @@ TEL;TYPE=WORK;TYPE=FAX;X-EVOLUTION-UI-SLOT=4:businessfax 4
 TEL;TYPE=HOME;TYPE=FAX;X-EVOLUTION-UI-SLOT=5:homefax 5
 TEL;TYPE=PAGER;X-EVOLUTION-UI-SLOT=6:pager 6
 TEL;TYPE=CAR;X-EVOLUTION-UI-SLOT=7:car 7
-TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 80
+TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 8xx
 X-AIM;X-EVOLUTION-UI-SLOT=1:AIM JOHN
 X-YAHOO;X-EVOLUTION-UI-SLOT=2:YAHOO JDOE
 X-ICQ;X-EVOLUTION-UI-SLOT=3:ICQ JD
index 9a91666..1b58643 100755 (executable)
@@ -13,7 +13,7 @@ for i in $IN/*; do
    # Modify second and third contact by changing a field.
    # The second contact will also get modified locally.
    perl -e '$_ = join("", <>); if (/John [23] Doe/) {' \
-       -e 's/primary 8/primary 80/;' \
+       -e 's/primary 8/primary 8xx/;' \
        -e 's/END:VCARD/BDAY:2006-01-01\r\nEMAIL:new local email\r\nEND:VCARD/;' \
        -e 'print;' \
        -e '}' \
index cc374af..afa6cb1 100755 (executable)
@@ -20,7 +20,7 @@ for i in $IN/*; do
    #
    # Each -e generates a line break, so no \n is necessary inside the expanded vCard.
    perl -e '$_ = join("", <>); if (/John [12] Doe/) {' \
-       -e 's/primary 8/primary 80/;' \
+       -e 's/primary 8/primary 8xx/;' \
        -e 's!END:VCARD!BDAY:2006-01-08\r' \
        -e 'TEL;TYPE=HOME:new remote tel 1\r' \
        -e 'tel2.TEL:new remote tel 2\r' \
index 36d65bc..3a3d300 100644 (file)
@@ -21,7 +21,7 @@ TEL;TYPE=FAX,WORK:businessfax 4
 TEL;TYPE=FAX,HOME:homefax 5\r
 TEL;TYPE=PAGER:pager 6\r
 TEL;TYPE=CAR:car 7\r
-TEL;TYPE=PREF:primary 80\r
+TEL;TYPE=PREF:primary 8xx\r
 EMAIL;TYPE=WORK:john.doe@work.com\r
 EMAIL;TYPE=HOME:john.doe@home.priv\r
 EMAIL:john.doe@other.world\r
@@ -133,7 +133,7 @@ TEL;TYPE=FAX,WORK:businessfax 4
 TEL;TYPE=FAX,HOME:homefax 5\r
 TEL;TYPE=PAGER:pager 6\r
 TEL;TYPE=CAR:car 7\r
-TEL;TYPE=PREF:primary 80\r
+TEL;TYPE=PREF:primary 8xx\r
 EMAIL;TYPE=WORK:john.doe@work.com\r
 EMAIL;TYPE=HOME:john.doe@home.priv\r
 EMAIL:john.doe@other.world\r
@@ -245,7 +245,7 @@ TEL;TYPE=FAX,WORK:businessfax 4
 TEL;TYPE=FAX,HOME:homefax 5\r
 TEL;TYPE=PAGER:pager 6\r
 TEL;TYPE=CAR:car 7\r
-TEL;TYPE=PREF:primary 80\r
+TEL;TYPE=PREF:primary 8xx\r
 EMAIL;TYPE=WORK:john.doe@work.com\r
 EMAIL;TYPE=HOME:john.doe@home.priv\r
 EMAIL:john.doe@other.world\r
index 652ac58..d19541e 100644 (file)
@@ -39,7 +39,7 @@ TEL;TYPE=WORK;TYPE=FAX:businessfax 4
 TEL;TYPE=HOME;TYPE=FAX:homefax 5
 TEL;TYPE=PAGER:pager 6
 TEL;TYPE=CAR:car 7
-TEL;TYPE=PREF:primary 80
+TEL;TYPE=PREF:primary 8xx
 X-AIM:AIM JOHN
 X-YAHOO:YAHOO JDOE
 X-ICQ:ICQ JD
@@ -127,7 +127,7 @@ TEL;TYPE=WORK;TYPE=FAX:businessfax 4
 TEL;TYPE=HOME;TYPE=FAX:homefax 5
 TEL;TYPE=PAGER:pager 6
 TEL;TYPE=CAR:car 7
-TEL;TYPE=PREF:primary 80
+TEL;TYPE=PREF:primary 8xx
 X-AIM:AIM JOHN
 X-YAHOO:YAHOO JDOE
 X-ICQ:ICQ JD
@@ -214,7 +214,7 @@ TEL;TYPE=WORK;TYPE=FAX;X-EVOLUTION-UI-SLOT=4:businessfax 4
 TEL;TYPE=HOME;TYPE=FAX;X-EVOLUTION-UI-SLOT=5:homefax 5
 TEL;TYPE=PAGER;X-EVOLUTION-UI-SLOT=6:pager 6
 TEL;TYPE=CAR;X-EVOLUTION-UI-SLOT=7:car 7
-TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 80
+TEL;TYPE=PREF;X-EVOLUTION-UI-SLOT=8:primary 8xx
 X-AIM;X-EVOLUTION-UI-SLOT=1:AIM JOHN
 X-YAHOO;X-EVOLUTION-UI-SLOT=2:YAHOO JDOE
 X-ICQ;X-EVOLUTION-UI-SLOT=3:ICQ JD
index 17a83b0..c3fcfb3 100755 (executable)
@@ -14,7 +14,7 @@ for i in $IN/*; do
    # The second contact will also get modified locally.
    # Add a different BDAY than the peer.
    perl -e '$_ = join("", <>); if (/John [23] Doe/) {' \
-       -e 's/primary 8/primary 80/;' \
+       -e 's/primary 8/primary 8xx/;' \
        -e 's/END:VCARD/BDAY:2006-01-01\r\nEMAIL:new local email\r\nEND:VCARD/;' \
        -e 'print;' \
        -e '}' \
index cc374af..afa6cb1 100755 (executable)
@@ -20,7 +20,7 @@ for i in $IN/*; do
    #
    # Each -e generates a line break, so no \n is necessary inside the expanded vCard.
    perl -e '$_ = join("", <>); if (/John [12] Doe/) {' \
-       -e 's/primary 8/primary 80/;' \
+       -e 's/primary 8/primary 8xx/;' \
        -e 's!END:VCARD!BDAY:2006-01-08\r' \
        -e 'TEL;TYPE=HOME:new remote tel 1\r' \
        -e 'tel2.TEL:new remote tel 2\r' \
index 7512689..350ad5d 100644 (file)
@@ -21,7 +21,7 @@ TEL;TYPE=FAX,WORK:businessfax 4
 TEL;TYPE=FAX,HOME:homefax 5\r
 TEL;TYPE=PAGER:pager 6\r
 TEL;TYPE=CAR:car 7\r
-TEL;TYPE=PREF:primary 80\r
+TEL;TYPE=PREF:primary 8xx\r
 EMAIL;TYPE=WORK:john.doe@work.com\r
 EMAIL;TYPE=HOME:john.doe@home.priv\r
 EMAIL:john.doe@other.world\r
@@ -133,7 +133,7 @@ TEL;TYPE=FAX,WORK:businessfax 4
 TEL;TYPE=FAX,HOME:homefax 5\r
 TEL;TYPE=PAGER:pager 6\r
 TEL;TYPE=CAR:car 7\r
-TEL;TYPE=PREF:primary 80\r
+TEL;TYPE=PREF:primary 8xx\r
 EMAIL;TYPE=WORK:john.doe@work.com\r
 EMAIL;TYPE=HOME:john.doe@home.priv\r
 EMAIL:john.doe@other.world\r
@@ -245,7 +245,7 @@ TEL;TYPE=FAX,WORK:businessfax 4
 TEL;TYPE=FAX,HOME:homefax 5\r
 TEL;TYPE=PAGER:pager 6\r
 TEL;TYPE=CAR:car 7\r
-TEL;TYPE=PREF:primary 80\r
+TEL;TYPE=PREF:primary 8xx\r
 EMAIL;TYPE=WORK:john.doe@work.com\r
 EMAIL;TYPE=HOME:john.doe@home.priv\r
 EMAIL:john.doe@other.world\r