# Generated by configure. Do no edit.
+2010-02-24 Patrick Ohly <patrick.ohly@intel.com>
+
+ * configure-pre.in:
+
+ minor version bump to 1.0beta2a because of Bluetooth dependency
+
+2010-02-24 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/eds_abi_wrapper.cpp:
+ * src/syncevo/eds_abi_wrapper.h:
+
+ libbluetooth: avoid dependency because of str2ba (MB #9289)
+
+2010-02-24 GLS_ITA <lorenzo.gennaro@ptiglobal.net>
+
+ * po/it.po:
+
+ l10n: Updates to Italian (it) translation
+
+2010-02-24 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: fix double free in error handling (MB #9869)
+
+2010-02-24 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: handle error 22002 (syncevolution died unexpectedly)
+
+2010-02-23 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: use bluetooth panel on Moblin
+
+2010-02-24 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ Server alerted sync: better error status (MB#8879)
+
+2010-02-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * NEWS:
+
+ NEWS: updated for 1.0 beta 2
+
+2010-02-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/backends/evolution/EvolutionCalendarSource.cpp:
+ * src/syncevo/TrackingSyncSource.h:
+ * test/ClientTest.cpp:
+
+ EvolutionCalendarSource: change tracking when deleting a child
+ event
+
+2010-02-23 GLS_ITA <lorenzo.gennaro@ptiglobal.net>
+
+ * po/it.po:
+
+ l10n: Updates to Italian (it) translation
+
+2010-02-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir::startSession(): avoid [ERROR] when logdir does not exist
+
+2010-02-23 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: fix possible crasher
+
+2010-02-23 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: use TemplatesChanged to update device list
+
+2010-02-23 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-server.c:
+ * src/dbus/syncevo-server.h:
+
+ dbus client bindings: implement TemplatesChanged
+
+2010-02-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/dbus/interfaces/syncevo-server-full.xml:
+ * src/syncevo-dbus-server.cpp:
+
+ D-Bus interface: added Server.TemplatesChanged (MB #9841)
+
+2010-02-23 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+
+ DBus server: clear existing templates for GetConfigs
+
+2010-02-23 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+ * src/syncevo/Cmdline.cpp:
+ * src/syncevo/SyncConfig.cpp:
+ * src/syncevo/SyncConfig.h:
+
+ DBus server: refine implementation of bluetooth devices
+
+2010-02-23 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/gdbus/gdbus-cxx-bridge.h:
+ * src/syncevo-dbus-server.cpp:
+
+ dbus server: listen to signals sent from bluez
+
+2010-02-22 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/eds_abi_wrapper.h:
+
+ libical _r patch: fix for compilation with older libecal
+
+2010-02-22 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/backends/evolution/EvolutionContactSource.cpp:
+ * src/backends/evolution/EvolutionSyncSource.cpp:
+
+ Evolution Address Book: avoid picking CouchDB by default, again
+ (MB #7877)
+
+2010-02-22 Patrick Ohly <patrick.ohly@intel.com>
+
+ * Makefile-gen.am:
+
+ syncevolution.org packages: conflict with system libs (MB #9811)
+
+2010-02-22 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncML.h:
+
+ sync session error: added STATUS_DIED_PREMATURELY = 22002 (MB
+ #9844)
+
+2010-02-20 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: don't use gtk_dialog_get_content_area()
+
+2010-02-22 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/backends/evolution/configure-sub.in:
+ * src/backends/evolution/libical/icalstrdup.c:
+ * src/backends/evolution/libical/icalstrdup.h:
+ * src/syncevo/eds_abi_wrapper.cpp:
+ * src/syncevo/eds_abi_wrapper.h:
+
+ workaround for libical 0.43 memory handling bug
+
+2010-02-19 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/util.cpp:
+
+ SHA-256 + Mozilla NSS: must call init
+
+2010-02-19 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ less output (MB #8092)
+
+2010-02-19 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ shorter logs (MB #8092)
+
+2010-02-19 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncConfig.cpp:
+
+ deviceId: use syncevolution- prefix, helps Horde (MB #9347)
+
+2010-02-19 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncConfig.cpp:
+
+ preventSlowSync: enabled by default (MB #2416)
+
+2010-02-19 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncConfig.cpp:
+
+ maxMsgSize: increased from 20000 to 150000
+
+2010-02-10 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: implement InfoRequest handling for passwords
+
+2010-02-10 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/interfaces/syncevo-marshal.list:
+ * src/dbus/syncevo-server.c:
+ * src/dbus/syncevo-server.h:
+
+ dbus client bindings: update InfoRequest signature
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/backends/evolution/EvolutionCalendarSourceRegister.cpp:
+ * src/backends/xmlrpc/XMLRPCSyncSourceRegister.cpp:
+
+ text/x-calendar -> text/x-vcalendar renaming was incomplete
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ SyncContext: fixed broken virtual source data format check
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir::expire(): CPPUnit testing (MB #7708)
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir::expire(): more intelligent removal of session dirs (MB
+ #7708)
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ SyncContext.cpp: added testing of session handling
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncML.cpp:
+ * src/syncevo/SyncML.h:
+
+ LogDir::startSession(): fixed collision check
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir::haveDifferentContent() - detect differences between
+ backups based on inodes
+
+2010-02-18 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir/SourceList::startSession(): removed obsolete "logname"
+ parameter
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * test/synccompare.pl:
+
+ synccompare: bug fix for recent hard linkining improvement
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncSource.h:
+ * src/syncevo/TrackingSyncSource.h:
+
+ database comparison: also delay it in clients (MB #7710)
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/backends/evolution/EvolutionCalendarSource.cpp:
+ * src/backends/evolution/EvolutionCalendarSource.h:
+ * src/backends/evolution/EvolutionContactSource.cpp:
+ * src/backends/evolution/EvolutionContactSource.h:
+ * src/backends/file/FileSyncSource.cpp:
+ * src/backends/file/FileSyncSource.h:
+ * src/backends/maemo/MaemoCalendarSource.cpp:
+ * src/backends/maemo/MaemoCalendarSource.h:
+ * src/backends/xmlrpc/XMLRPCSyncSource.cpp:
+ * src/backends/xmlrpc/XMLRPCSyncSource.h:
+ * src/syncevo/TrackingSyncSource.cpp:
+ * src/syncevo/TrackingSyncSource.h:
+
+ TrackingSyncSource: added isEmpty() pure virtual method (MB
+ #7708)
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/backends/sqlite/SQLiteContactSource.cpp:
+ * src/backends/sqlite/SQLiteContactSource.h:
+
+ SQLite backend: implement m_isEmpty operation (MB #7708)
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncSource.h:
+
+ SyncSource API: added m_isEmpty operation (MB #7708)
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncSource.cpp:
+ * src/syncevo/SyncSource.h:
+ * test/ClientTest.cpp:
+
+ SyncSourceRevisions: cache result of listAllItems() (MB #7708)
+
+2010-02-16 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ SAN + virtual source: segfault fixed (MB #9737)
+
+2010-02-15 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncContext.h:
+
+ virtual sources: avoid name collisions with normal sources (MB
+ #9664)
+
+2010-02-15 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ XMLFiles::addFragments(): avoid throwing exceptions by checking
+ for dir first
+
+2010-02-15 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/Cmdline.cpp:
+ * src/syncevo/SyncConfig.cpp:
+ * src/syncevo/SyncConfig.h:
+ * src/syncevo/SyncContext.cpp:
+
+ <dbtypeid>: handle hash collisisions
+
+2010-02-15 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncContext.h:
+
+ SyncContext::prepare(sources): removed, obsolete
+
+2010-02-15 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ virtual datastore: allow alias (MB #9664)
+
+2010-02-15 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/ObexTransportAgent.cpp:
+ * src/syncevo/eds_abi_wrapper.cpp:
+ * src/syncevo/eds_abi_wrapper.h:
+
+ libbluetooth compatibility layer (MB #9289)
+
+2010-02-10 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ virtual source in client: tell engine about superdatastore and
+ URI
+
+2010-02-12 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncML.cpp:
+ * src/syncevo/SyncML.h:
+
+ slow sync detection + virtual source: fixed user message
+
+2010-02-12 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ virtual data sources: improved error handling
+
+2010-02-10 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncContext.h:
+
+ SyncML server: delayed checking of sources (MB #7710)
+
+2010-02-10 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncSource.h:
+ * src/syncevo/SynthesisDBPlugin.cpp:
+
+ SyncSource::Operations: added callback for starting to use source
+
+2010-02-19 zerng07 <pswo10680@gmail.com>
+
+ * po/zh_TW.po:
+
+ l10n: Updates to Chinese (Taiwan) (zh_TW) translation
+
+2010-02-19 zerng07 <pswo10680@gmail.com>
+
+ * po/zh_TW.po:
+
+ l10n: Updates to Chinese (Taiwan) (zh_TW) translation
+
+2010-02-18 zerng07 <pswo10680@gmail.com>
+
+ * po/zh_TW.po:
+
+ l10n: Updates to Chinese (Taiwan) (zh_TW) translation
+
+2010-02-18 zerng07 <pswo10680@gmail.com>
+
+ * po/zh_TW.po:
+
+ l10n: Updates to Chinese (Taiwan) (zh_TW) translation
+
+2010-02-10 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/sync-ui.h:
+
+ gtk-ui: backup-restore improvements
+
+2010-02-10 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: fix keyboard access in configuration
+
+2010-02-10 Jussi Kukkonen <jku@linux.intel.com>
+
+ * configure-pre.in:
+
+ gtk-ui: fix build with --enable-gui again (MB #9633)
+
+2010-02-10 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: show main view when restoring backup (MB #9617)
+
+2010-02-10 Patrick Ohly <patrick.ohly@intel.com>
+
+ * build/export-synthesis-xml.sh:
+
+ export-synthesis-xml.sh: export Synthesis XML fragment patches
+
+2010-02-10 Patrick Ohly <patrick.ohly@intel.com>
+
+ * build/export-gdbus.sh:
+
+ export-gdbus.sh: fixed incorrect comment
+
+2010-02-10 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo/ObexTransportAgent.cpp:
+
+ ObexTransportAgent: error handling
+
+2010-02-10 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo/ObexTransportAgent.cpp:
+
+ ObexTransportAgent: remove the non-blocking
+ g_main_context_iteration
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ detecting slow sync: use LOCERR_DATASTORE_ABORT (MB #2416)
+
+2010-01-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ SyncML server: remove redundant SourceConfigSpecials
+
+2010-01-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ slow sync detection: use <datastoreinitscript> instead of
+ <alertscript> (MB #2416)
+
+2010-01-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncSource.h:
+
+ SAN + forced slow sync: move flag into SyncSource
+
+2010-02-09 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+ * src/syncevo/ObexTransportAgent.cpp:
+ * src/syncevo/ObexTransportAgent.h:
+ * src/syncevo/SoupTransportAgent.cpp:
+ * src/syncevo/SoupTransportAgent.h:
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncContext.h:
+
+ syncevo-dbus-server + OBEX: transport was not enabled (MB #9436)
+
+2010-02-09 Patrick Ohly <patrick.ohly@intel.com>
+
+ * configure-post.in:
+
+ autotools: fixed check for glib > 2.16
+
+2010-02-09 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/Makefile-gen.am:
+ * src/gnome-bluetooth/Makefile.am:
+ * src/syncevo/configs/Makefile.am:
+
+ autotools: some more fixes
+
+2010-02-09 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+
+ syncevo-dbus-server: fix GetConfigs() hang
+
+2010-02-09 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: start bluetooth wizard when Add device clicked
+
+2010-02-09 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-dbus-types.c:
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: use "fingerprint" for device template selector
+
+2010-02-08 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncSource.cpp:
+ * src/syncevo/SyncSource.h:
+
+ virtual source: support D-Bus CheckSource() (MB #9535)
+
+2010-02-08 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncSource.cpp:
+
+ database dumps: use SHA-256 when available (MB #7708)
+
+2010-02-08 Patrick Ohly <patrick.ohly@intel.com>
+
+ * README:
+ * README.packagers:
+ * configure-post.in:
+ * src/syncevo/Makefile.am:
+ * src/syncevo/util.cpp:
+ * src/syncevo/util.h:
+
+ SHA-256: use glib or Mozilla NSS
+
+2010-02-08 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SmartPtr.h:
+
+ SmartPtr: added smart pointer for glib char string
+
+2010-02-08 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ command line: compare against dump in last session involving
+ source (MB #7708)
+
+2010-02-07 Patrick Ohly <patrick.ohly@intel.com>
+
+ * test/synccompare.pl:
+
+ synccompare: don't include identical files in comparison (MB
+ #7708)
+
+2010-02-06 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncSource.cpp:
+
+ SyncSourceRevisions: reuse data files from previous backup (MB
+ #7708)
+
+2010-02-06 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/util.cpp:
+ * src/syncevo/util.h:
+
+ Hash(): added version for std::string
+
+2010-02-06 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/ConfigNode.h:
+
+ ConfigNode::getProperty(): added const declaration
+
+2010-02-05 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ SourceList: determine most recent backup of source when making
+ next backup (MB #7708)
+
+2010-02-05 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir: fixed finding sessions inside non-standard context with
+ escaped chars
+
+2010-02-05 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncSource.cpp:
+ * src/syncevo/SyncSource.h:
+ * test/ClientTest.cpp:
+
+ SyncSource API: access to previous backup (MB #7708)
+
+2010-02-08 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncContext.cpp:
+
+ LogDir: cleanup
+
+2010-02-08 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/sync-ui.h:
+
+ gtk-ui: workaround for missing "active" in MxGtkLightSwitch
+
+2010-02-08 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: ask for 1024 window width for gtk windows
+
+2010-02-08 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/sync-ui.h:
+
+ gtk-ui: improve confirmation dialogs
+
+2010-02-08 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: improve virtual source display in config
+
+2010-02-08 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-dbus-types.c:
+
+ dbus client bindings: handle no mode as "none"
+
+2010-02-08 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-config-widget.h:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: changes in config api
+
+2010-02-06 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+
+ gtk-ui: hide virtual sources when not usable + other tweaks
+
+2010-02-06 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: escape source names when using markup
+
+2010-02-05 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/sync-ui.h:
+
+ gtk-ui: improve slow sync messages
+
+2010-02-03 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-config-widget.h:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: very rough draft of device template selection
+
+2010-02-03 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+
+ gtk-ui: don't require username/password for device configs
+
+2010-02-02 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-config-widget.h:
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: layout & code updates for device config UI
+
+2010-02-02 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-config-widget.h:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: modify SyncConfigWidget for device sync changes
+
+2010-02-03 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/dbus/interfaces/syncevo-server-full.xml:
+ * src/gdbus/gdbus-cxx-bridge.h:
+ * src/syncevo-dbus-server.cpp:
+ * src/syncevo/Cmdline.cpp:
+ * src/syncevo/SyncConfig.cpp:
+ * src/syncevo/SyncConfig.h:
+
+ DBus server: Implement GetConfigs with device querying(MB#9216)
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/Makefile-gen.am:
+
+ autotools: gnome-bluetooth + make dist
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/Makefile.am:
+
+ SyncEvolutionXML.c: treat it as generated file
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncConfig.cpp:
+
+ syncURL: updated description (MB #9446)
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncConfig.cpp:
+
+ SyncConfig::getSyncURL(): workaround for g++ 4.3/4.4 bug
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * README:
+ * README.packagers:
+ * configure-post.in:
+ * configure-pre.in:
+ * po/POTFILES.in:
+ * src/Makefile-gen.am:
+ * src/gnome-bluetooth/Makefile.am:
+ * src/gnome-bluetooth/configure-sub.in:
+
+ autotools: build GNOME Bluetooth panel plugin (MB #7089)
+
+2010-02-03 Chen Congwu <congwu.chen@intel.com>
+
+ * src/gnome-bluetooth/syncevolution.c:
+
+ Bluetooth pairing integration (MB#7089)
+
+2010-02-04 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+
+ Presence detection: bug fix
+
+2010-02-04 Jussi Kukkonen <jku@linux.intel.com>
+
+ * configure-pre.in:
+
+ fix build with "--enable-gui=all"
+
+2010-02-04 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/main.c:
+
+ gtk-ui: don't open two main windows (MB #9449)
+
+2010-02-04 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: fix suspicious string array handling (MB #9434)
+
+2010-02-03 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+
+ DBusServer: coding convention changes
+
+2010-02-03 Chen Congwu <congwu.chen@intel.com>
+
+ * src/gdbus/gdbus-cxx-bridge.h:
+
+ gdbus-cxx-bridge: Copy DBusCallObject member to be more safe
+
+2010-02-03 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/main.c:
+
+ gtk-ui: fix another problem with non-libunique build
+
+2010-02-03 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/gtk-ui/main.c:
+
+ gtk-gui: fixed compiler error when not having libunique
+
+2010-02-03 Patrick Ohly <patrick.ohly@intel.com>
+
+ * configure-pre.in:
+
+ post-release version bump
+
+2010-02-02 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: forgot to change source naming Memo->Notes
+
+2010-02-01 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+
+ gtk-ui: --show-settings should match url prefix (MB #9284)
+
+2010-02-01 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: ellipsize very long service name in main view
+
+2010-02-01 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: make config usable with long strings (MB #9278)
+
+2010-01-28 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: remember to update service list when it is shown
+
+2010-01-28 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-dbus-types.c:
+ * src/dbus/syncevo-dbus-types.h:
+ * src/gtk-ui/sync-ui-config.h:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: handle source phases correctly (MB #9320)
+
+2010-01-28 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: Fix error output
+
+2010-01-28 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-dbus-types.c:
+ * src/dbus/syncevo-dbus-types.h:
+ * src/gtk-ui/Makefile.am:
+ * src/gtk-ui/sync-spinner.gif:
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: show status "waiting" with a progress spinner
+
+2010-01-28 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui-config.c:
+ * src/gtk-ui/sync-ui-config.h:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: don't allow non-defined sources in emergency
+
+2010-01-27 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui-config.c:
+ * src/gtk-ui/sync-ui-config.h:
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: use PeerName property for user visible names
+
+2010-01-27 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: tweak emergency view layout, modify strings
+
+2010-01-27 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-dbus-types.c:
+
+ dbus client bindings: fix syncevo_config_get_value() return value
+
+2010-01-26 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/main.c:
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-config-widget.h:
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/sync-ui.h:
+
+ gtk-ui: support "--show-settings <id>"
+
+2010-01-26 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: only ask for backups for correct context
+
+2010-01-26 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: string and style changes
+
+2010-01-26 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/mux-window.c:
+ * src/gtk-ui/mux-window.h:
+ * src/gtk-ui/sync-config-widget.c:
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: change bread-crumb functionality in moblin
+
+2010-01-25 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: don't show "last synced ..." when last sync failed
+
+2010-01-25 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+
+ gtk-ui: only show backups that contain selected sources
+
+2010-01-25 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: implement restoring backups
+
+2010-01-25 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/dbus/syncevo-session.c:
+ * src/dbus/syncevo-session.h:
+
+ dbus bindings: add Session.Restore()
+
+2010-01-25 Jussi Kukkonen <jku@linux.intel.com>
+
+ * src/gtk-ui/sync-ui.c:
+ * src/gtk-ui/ui.glade:
+
+ gtk-ui: remove uneeded "Data" text from main view
+
+2010-01-29 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+ * src/syncevo/SyncConfig.cpp:
+ * src/syncevo/SyncConfig.h:
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncContext.h:
+
+ SyncURL: support multiple transport values in SyncURL property
+
+2010-02-03 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+ * test/test-dbus.py:
+
+ Presence detection: connman part (MB#7700)
+
+2010-02-02 Chen Congwu <congwu.chen@intel.com>
+
+ * src/gdbus/gdbus-cxx-bridge.h:
+
+ gdbus: cxxbridge for asynchronous dbus client call
+
+2010-02-02 Patrick Ohly <patrick.ohly@intel.com>
+
+ * configure-post.in:
+ * src/Makefile-gen.am:
+ * src/sunbird_client.xml:
+ * src/syncclient_sample_config.xml:
+ * src/syncevo/Makefile.am:
+ * src/syncevo/SyncContext.cpp:
+ * src/syncevo/SyncContext.h:
+ * src/syncevo/configs/Makefile.am:
+ * src/syncevo/configs/syncevolution.xml:
+ * src/syncevo/configs/update-samples.pl:
+
+ XML config: use configuration composed from fragments (MB #7712)
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+
+ XML config: avoid empty LOCATION in VEVENT
+
+2010-01-22 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/00vcard-fieldlist.xml:
+ * src/syncevo/configs/datatypes/01vcard-profile.xml:
+
+ syncclient_sample_config.xml: added "GENDER" and "SIP"
+
+2009-12-18 Rajyalakshmi Bommaraju <Rajyalakshmi.Bommaraju@intel.com>
+
+ * src/syncevo/configs/datatypes/02vcard-types.xml:
+ * src/syncevo/configs/scripting/06vcard-fullname.xml:
+
+ syncclient_sample_config.xml: create fullname if empty (MB#5664)
+
+2010-01-06 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/datatypes/00vcard-fieldlist.xml:
+ * src/syncevo/configs/datatypes/01vcard-profile.xml:
+
+ Config: add support for 'X-SKYPE' for evolution (MB#8948)
+
+2009-12-11 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+
+ synthesis config: add "STATUS" property to "VEVENT" profile.
+
+2009-12-01 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/remoterules/client/00zyb.xml:
+
+ syncclient config: disable anchors checking for ZYB(MB#8138)
+
+2009-10-15 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/scripting/06todo-priorities.xml:
+ * src/syncevo/configs/scripting/11calendar.xml:
+
+ SyncSource: Add 'prioprity' conversion between vCalendar1.0 and
+ 2.0
+
+2009-10-15 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/scripting/05vcard-evolution.xml:
+
+ SyncSource: change names for m_incomingScript and
+ m_outgointScript
+
+2009-10-06 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/scripting/05vcard-evolution.xml:
+
+ Google->Evolution: make sure that WORK/HOME numbers are displayed
+ (MB #6501)
+
+2009-08-29 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/scripting/05vcard-evolution.xml:
+
+ Memotoo: add a workaround for 'TEL' with 'cell' type(bug#5633)
+
+2009-08-06 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/scripting/11calendar.xml:
+
+ Mobical: Strip time information for EXDATE if not needed (Bug
+ #3009)
+
+2009-07-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/scripting/11calendar.xml:
+
+ calendar support: sanitize incoming EXDATEs (Bugzilla #4457)
+
+2009-07-15 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/scripting/11calendar.xml:
+
+ Funambol: A workaround for 'ACTION' lost by Funambol server (Bug
+ #2422)
+
+2009-06-25 zhu, yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+
+ iCal20: Add 'suppressempty="yes"' for 'LAST-MODIFIED'
+ property(Bug #2422)
+
+2009-06-24 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/01vcard-profile.xml:
+
+ vCard: support X-MANAGER/ASSISTANT/SPOUSE/ANNIVERSARY (Bugzilla
+ #2418)
+
+2009-06-24 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/remoterules/evolution.xml:
+
+ data conversion: different data profiles for SyncML peer + local
+ DB with remote rules
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/scripting/11calendar.xml:
+
+ XML config: keep alarm times as they are
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+
+ XML config: be conservative about encoding of EXDATEs
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/10calendar-fieldlist.xml:
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+
+ XML config: enhanced calendar data formats
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/00vcard-fieldlist.xml:
+ * src/syncevo/configs/datatypes/01vcard-profile.xml:
+
+ XML config: added several vCard 3.0/Evolution specific properties
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/00vcard-fieldlist.xml:
+
+ XML config: don't enforce http:// prefix in vCard 2.1 URL
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/01vcard-profile.xml:
+
+ XML config: use NICKNAME also in vCard 2.1
+
+2009-06-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+ * src/syncevo/configs/scripting/11calendar.xml:
+
+ XML config: don't encode empty DESCRIPTION in VEVENT/VTODO
+
+2010-02-02 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/update-samples.pl:
+
+ update-samples.pl: accept command line parameters for updating a
+ specific file
+
+2010-02-01 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/configs/README:
+ * src/syncevo/configs/datatypes/00vcard-fieldlist.xml:
+ * src/syncevo/configs/datatypes/01vcard-profile.xml:
+ * src/syncevo/configs/datatypes/02vcard-types.xml:
+ * src/syncevo/configs/datatypes/10calendar-fieldlist.xml:
+ * src/syncevo/configs/datatypes/11calendar-profile.xml:
+ * src/syncevo/configs/datatypes/12calendar-types.xml:
+ * src/syncevo/configs/datatypes/20note-fieldlist.xml:
+ * src/syncevo/configs/datatypes/21note-profile.xml:
+ * src/syncevo/configs/datatypes/22notes-types.xml:
+ * src/syncevo/configs/datatypes/30bookmark-fieldlist.xml:
+ * src/syncevo/configs/datatypes/31bookmark-profile.xml:
+ * src/syncevo/configs/datatypes/32bookmark-type.xml:
+ * src/syncevo/configs/datatypes/server/40email-fieldlist.xml:
+ * src/syncevo/configs/datatypes/server/41email-profile.xml:
+ * src/syncevo/configs/datatypes/server/42email-type-zipped.xml:
+ * src/syncevo/configs/datatypes/server/42email-type.xml:
+ * src/syncevo/configs/datatypes/server/43email-sonyericsson.xml:
+ * src/syncevo/configs/datatypes/server/44email-nokia9500.xml:
+ * src/syncevo/configs/debug/00default.xml:
+ * src/syncevo/configs/remoterules/server/00_t39m.xml:
+ * src/syncevo/configs/remoterules/server/01_t68.xml:
+ * src/syncevo/configs/remoterules/server/02_V3.xml:
+ * src/syncevo/configs/remoterules/server/03_V3i.xml:
+ * src/syncevo/configs/remoterules/server/04_6230.xml:
+ * src/syncevo/configs/remoterules/server/05_9210.xml:
+ * src/syncevo/configs/remoterules/server/06_9210i.xml:
+ * src/syncevo/configs/remoterules/server/07_3220.xml:
+ * src/syncevo/configs/remoterules/server/08_3230.xml:
+ * src/syncevo/configs/remoterules/server/09_3600.xml:
+ * src/syncevo/configs/remoterules/server/10_3620.xml:
+ * src/syncevo/configs/remoterules/server/11_3650.xml:
+ * src/syncevo/configs/remoterules/server/12_3660.xml:
+ * src/syncevo/configs/remoterules/server/13_6260.xml:
+ * src/syncevo/configs/remoterules/server/14_6600.xml:
+ * src/syncevo/configs/remoterules/server/15_6620.xml:
+ * src/syncevo/configs/remoterules/server/16_6630.xml:
+ * src/syncevo/configs/remoterules/server/17_6670.xml:
+ * src/syncevo/configs/remoterules/server/18_7250.xml:
+ * src/syncevo/configs/remoterules/server/19_7250i.xml:
+ * src/syncevo/configs/remoterules/server/20_7260.xml:
+ * src/syncevo/configs/remoterules/server/21_7610.xml:
+ * src/syncevo/configs/remoterules/server/22_7650.xml:
+ * src/syncevo/configs/remoterules/server/23_N-Gage.xml:
+ * src/syncevo/configs/remoterules/server/24_N-Gage_QD.xml:
+ * src/syncevo/configs/remoterules/server/25_9300.xml:
+ * src/syncevo/configs/remoterules/server/26_9500.xml:
+ * src/syncevo/configs/remoterules/server/27_E90.xml:
+ * src/syncevo/configs/remoterules/server/28_X.xml:
+ * src/syncevo/configs/remoterules/server/29_SX1.xml:
+ * src/syncevo/configs/remoterules/server/30_M55.xml:
+ * src/syncevo/configs/remoterules/server/31_SL55.xml:
+ * src/syncevo/configs/remoterules/server/32_S55.xml:
+ * src/syncevo/configs/remoterules/server/33_S65.xml:
+ * src/syncevo/configs/remoterules/server/34_SL65.xml:
+ * src/syncevo/configs/remoterules/server/35_K700.xml:
+ * src/syncevo/configs/remoterules/server/36_T610_T630.xml:
+ * src/syncevo/configs/remoterules/server/37_M600i.xml:
+ * src/syncevo/configs/remoterules/server/38_P800.xml:
+ * src/syncevo/configs/remoterules/server/39_P900.xml:
+ * src/syncevo/configs/remoterules/server/40_P910.xml:
+ * src/syncevo/configs/remoterules/server/41_P910i.xml:
+ * src/syncevo/configs/remoterules/server/42_P990i.xml:
+ * src/syncevo/configs/remoterules/server/43_t68i.xml:
+ * src/syncevo/configs/remoterules/server/44_Funambol_Outlook.xml:
+ * src/syncevo/configs/remoterules/server/45_SyncJe_Outlook.xml:
+ * src/syncevo/configs/scripting/10newuid.xml:
+ * src/syncevo/configs/scripting/11calendar.xml:
+ * src/syncevo/configs/scripting/client/00timeout.xml:
+ * src/syncevo/configs/scripting/server/12email.xml:
+ * src/syncevo/configs/update-samples.pl:
+
+ XML config samples: split up into individual fragments
+
+2010-02-02 Patrick Ohly <patrick.ohly@intel.com>
+
+ * build/import-synthesis-xml.sh:
+
+ import-synthesis-xml.sh: import shared XML config fragments (MB
+ #7712)
+
+2010-02-02 Patrick Ohly <patrick.ohly@intel.com>
+
+ * build/import-foreign-git.sh:
+
+ import-foreign-git.sh: allow non-existing files
+
+2010-02-02 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * test/test-dbus.py:
+
+ Testing: apply default and user setting local databases (MB#9332)
+
+2010-02-01 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * src/syncevo-dbus-server.cpp:
+ * test/test-dbus.py:
+
+ DBus server: return real passwords for GetConfig (MB#9169)
+
+2010-01-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/Cmdline.cpp:
+ * src/syncevo/SyncConfig.cpp:
+
+ config: adding sources affects peers in the same context (MB
+ #9329)
+
+2010-01-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/SyncConfig.cpp:
+ * src/syncevo/SyncConfig.h:
+
+ command line: wrong context during --configure (MB #9338)
+
+2010-01-29 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/syncevo/Cmdline.cpp:
+ * src/syncevo/util.cpp:
+ * src/syncevo/util.h:
+
+ ScopedEnvChange: moved from Cmdline.cpp to util
+
+2010-01-28 Patrick Ohly <patrick.ohly@intel.com>
+
+ * configure-pre.in:
+
+ autotools: removed obsolete libbluetooth2/3 check (MB #9260)
+
+2010-01-21 Zhu, Yongsheng <yongsheng.zhu@intel.com>
+
+ * test/test-dbus.py:
+
+ Testing: fix failures and remove dependency for test-dbus.py
+ (MB#9065)
+
2010-01-27 Patrick Ohly <patrick.ohly@intel.com>
* configure-pre.in:
#
# --replaces is necessary for migrating from syncevolution-evolution-<evover>
# to syncevolution-evolution (as per http://wiki.debian.org/Renaming_a_Package)
+#
+# When we build shared objects, then conflict with the corresponding
+# system libs. The assumption is that the system library is named
+# after the lib and its major version, which holds for libsmltk and
+# libsynthesis in Debian.
deb rpm : dist/$(distdir) dist/debian/control description-pak
+ conflicts=`ls -1 dist/$(distdir)/usr/lib/*.so.[0123456789] | sed -e 's;.*/;;' -e 's/\.so\.//' -e 's/$$/, /'` && \
tmpdir=`mktemp -d $$HOME/syncevolution.XXXXXXXXXX` && \
trap "rm -rf $$tmpdir" EXIT && \
fakeroot checkinstall </dev/null \
--pkgarch=$(PKGARCH) \
--provides=syncevolution \
--replaces="'syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
- --conflicts="'syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
+ --conflicts="'$${conflicts}syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
--maintainer="'Patrick Ohly <patrick.ohly@gmx.de>'" \
--pkgsource='http://sourceforge.net/project/showfiles.php?group_id=146288' \
--pkgaltsource='http://www.estamos.de/projects/SyncML/' \
#
# --replaces is necessary for migrating from syncevolution-evolution-<evover>
# to syncevolution-evolution (as per http://wiki.debian.org/Renaming_a_Package)
+#
+# When we build shared objects, then conflict with the corresponding
+# system libs. The assumption is that the system library is named
+# after the lib and its major version, which holds for libsmltk and
+# libsynthesis in Debian.
deb rpm : dist/$(distdir) dist/debian/control description-pak
+ conflicts=`ls -1 dist/$(distdir)/usr/lib/*.so.[0123456789] | sed -e 's;.*/;;' -e 's/\.so\.//' -e 's/$$/, /'` && \
tmpdir=`mktemp -d $$HOME/syncevolution.XXXXXXXXXX` && \
trap "rm -rf $$tmpdir" EXIT && \
fakeroot checkinstall </dev/null \
--pkgarch=$(PKGARCH) \
--provides=syncevolution \
--replaces="'syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
- --conflicts="'syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
+ --conflicts="'$${conflicts}syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
--maintainer="'Patrick Ohly <patrick.ohly@gmx.de>'" \
--pkgsource='http://sourceforge.net/project/showfiles.php?group_id=146288' \
--pkgaltsource='http://www.estamos.de/projects/SyncML/' \
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
#
# --replaces is necessary for migrating from syncevolution-evolution-<evover>
# to syncevolution-evolution (as per http://wiki.debian.org/Renaming_a_Package)
+#
+# When we build shared objects, then conflict with the corresponding
+# system libs. The assumption is that the system library is named
+# after the lib and its major version, which holds for libsmltk and
+# libsynthesis in Debian.
deb rpm : dist/$(distdir) dist/debian/control description-pak
+ conflicts=`ls -1 dist/$(distdir)/usr/lib/*.so.[0123456789] | sed -e 's;.*/;;' -e 's/\.so\.//' -e 's/$$/, /'` && \
tmpdir=`mktemp -d $$HOME/syncevolution.XXXXXXXXXX` && \
trap "rm -rf $$tmpdir" EXIT && \
fakeroot checkinstall </dev/null \
--pkgarch=$(PKGARCH) \
--provides=syncevolution \
--replaces="'syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
- --conflicts="'syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
+ --conflicts="'$${conflicts}syncevolution, `echo $(filter-out $(PKGNAME), $(PKGS)) | sed -e 's/ */ (<< 1:0.8.1-2), /g'` (<< 1:0.8.1-2)'" \
--maintainer="'Patrick Ohly <patrick.ohly@gmx.de>'" \
--pkgsource='http://sourceforge.net/project/showfiles.php?group_id=146288' \
--pkgaltsource='http://www.estamos.de/projects/SyncML/' \
+SyncEvolution 1.0 beta 1 -> beta 2, 23.02.2010
+==============================================
+
+Several new features and some bug fixing. Despite some open issues
+(see below), this release is ready for getting packaged in staging
+areas of distros as replacement for 0.9.2.
+
+As before, documentation for 1.0 is only available in the
+"Development" section of syncevolution.org, including HOWTOs for
+setting up the HTTP SyncML server and phones manually.
+
+Setting up a phone became a bit easier with beta 2, because
+SyncEvolution is now integrated with the GNOME Bluetooth panel: once a
+device with SyncML client support is paired, a button offers to bring
+up the sync-UI and configure or synchronize with that device. We do a
+fuzzy match against the Bluetooth device name to find a suitable
+template (not manufacturer/model, because that is not readily
+available). Still not many (read: hardly any) templates available,
+though.
+
+The binaries on syncevolution.org are compiled with Bluetooth support.
+libbluetooth2 or libbluetooth3 should be installed, but are not
+essential. If there is no suitable version of it, the Bluetooth
+channel has to be selected manually as part of the syncURL.
+
+Unexpected slow syncs are prevented by default, in contrast to beta 1
+where this feature was available but turned off. When an unexpected
+slow sync is detected in a client, users have to follow the
+instructions provided by the command line or sync-ui and choose how to
+proceed (explicitly request slow sync, refresh from server or client,
+restore from backup). SyncEvolution as server currently cannot prevent
+slow syncs, even when initiating the sync with a phone.
+
+In preparation for syncing automatically, logdir and database handling
+was improved considerably. Backups use less disk space because
+identical files share the same file content via hard links. This also
+speeds up the synccompare Perl script. Database dumps and the
+corresponding comparison are delayed until the session really runs,
+which avoids doing needless work a) when the server a client tries to
+contact is unreachable or down and b) by only including sources that
+are really in use during a sync on the server side.
+
+The Synthesis XML configuration was split up into different parts
+which are assembled from /usr/share/syncevolution/xml. Files in
+~/.config/syncevolution-xml override and extend the default files,
+which my be useful when adding support for a new phone.
+
+
+Summary of changes since 1.0 beta 1:
+
+* sync-ui: recovery dialog (MB #8050), device setup, config usable with
+ long strings (MB #9278), fixed displaying of source phases during sync
+ (MB #9320)
+* sync-ui + syncevo-dbus-server: integration with Bluez to detect paired
+ devices (MB #9216, MB #7089), select template based on device name (MB #7838),
+ detect network and Bluetooth connectivity (only with ConnMan, MB #7700),
+ passwords stored in GNOME keyring by syncevo-dbus-server are shown with
+ dots in sync-ui (MB #9169)
+* Evolution addressbook backend: avoid picking CouchDB, second try (MB #7877)
+* Evolution calendar backend: minor fix for change tracking when deleting
+ a single instance of a recurring event
+* build fixes: Bluetooth compatibility (MB #9289), use libical _r variant
+ of calls because 0.43 has issues in the normal version, conflict with
+ system libsynthesis and libsmltk (MB #9811)
+* Horde: avoid confusing the server with a deviceId that starts like the
+ ones used in old Funambol clients, helps with calendar sync (MB #9347)
+* better reporting when SyncEvolution dies during a sync (only happend once
+ when it wasn't installed properly, but still... MB #9844)
+* performance improvements: synccompare much faster/database dumps consume
+ less disk space/more intelligent about expiring obsolete session directories
+ and backups/database accesses are reduced in several backends (MB #7708),
+ shorter logs (MB #8092)
+* slow sync detection: now also works in the case where the client detects
+ an anchor mismatch and enabled by default (MB #2416)
+* OBEX transport: some error handling changes and removal of polling, now
+ also possible via sync-ui + syncevo-dbus-server (MB #9436)
+* API changes: SyncSource introduces an "isEmpty" operation which is
+ needed for the slow sync detection
+* SyncML: split up configuration (MB #7712), increased default message size
+ because the old one might have been too small for large DevInf structures
+* several fixes for virtual data sources ("calendar+todo"): now works
+ on client side, fixed naming on server (MB #9664), fixed error message
+ for slow sync detection, supported in combination with sync-UI (MB #9535)
+* fixes for shared configuration layout: finding sessions of peers in
+ non-default context, adding sources affected peers in the same context
+ (MB #9329), wrong context during --configure when using shortcut for peers
+ in non-default context (MB #9338)
+
+
+Known gaps for 1.0 final and beyond:
+
+Redesigned and reimplemented D-Bus API, required by sync-UI:
+- 'syncevolution' command line tool bypasses D-Bus server and runs
+ sync sessions itself (MB #5043)
+- availability of peers not detected when using NetworkManager
+ (connected for HTTP, paired for Bluetooth; MB #7700)
+
+SyncML server in general:
+- suspend/resume support is untested (MB #2425)
+- the progress events and statistics reported for a SyncML client
+ are not generated when running as SyncML server, will require
+ a fair amount of refactoring in the Synthesis engine (MB #7709)
+
+HTTP SyncML server:
+- a configuration must be created for each peer manually, including
+ a remoteDeviceId value that contains the peer's SyncML device ID
+ (MB #7838)
+
+OBEX SyncML server ("sync with phones"):
+- does not support phones which require a SAN 1.0 message (MB #9312)
+- determining a working configuration for an unknown phone requires
+ a bit of experimenting, which should be automated (MB #9862)
+
+OBEX SyncML client:
+- parsing of SAN message is rudimentary and depends on an existing local
+ configuration, needs to be refined depending on which SyncML server software
+ it is meant to work with (MB #6175)
+
+Automatic sync (MB #6378):
+- no support for the various server push notification mechanisms
+- no intelligent detection of local changes
+- no regular background sync, development is in progress
+
+Upgrading from 1.0 beta 1: moving back and forth should work seamlessly
+Upgrading from 0.9.x: see under beta 1
+
+
SyncEvolution 0.9.2 -> 1.0 beta 1, 26.01.2010
==============================================
Optional (enables direct sync with phones):
apt-get install libopenobex-dev libbluetooth-dev
+Optional (only used for SHA-256 when glib is not already a dependency):
+ apt-get install libnss3-dev
+
For compiling libsynthesis:
apt-get install libpcre3-dev libsqlite3-dev libexpat-dev libz-dev
libunique = ensure that GTK GUI only runs once per user
+Optional packages for GNOME Bluetooth Panel plugin:
+ apt-get install libgnome-bluetooth-dev
+
+The plugin adds a button to invoke sync-UI after a device
+was paired which supports SyncML.
+
The build system is the normal autotools system. See INSTALL for
general instructions how to use that and "./configure --help" for
SyncEvolution specific options.
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* have recent enough libical with _r variants */
+#undef HAVE_LIBICAL_R
+
/* enable GNOME specific libsoup */
#undef HAVE_LIBSOUP_SOUP_GNOME_FEATURES_H
/* Use Moblin UI widgets */
#undef USE_MOBLIN_UX
+/* choose implementation of SHA-256 */
+#undef USE_SHA256
+
/* Version number of package */
#undef VERSION
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for syncevolution 1.0beta1.
+# Generated by GNU Autoconf 2.61 for syncevolution 1.0beta2a.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# Identity of this package.
PACKAGE_NAME='syncevolution'
PACKAGE_TARNAME='syncevolution'
-PACKAGE_VERSION='1.0beta1'
-PACKAGE_STRING='syncevolution 1.0beta1'
+PACKAGE_VERSION='1.0beta2a'
+PACKAGE_STRING='syncevolution 1.0beta2a'
PACKAGE_BUGREPORT=''
# Factoring default headers for most tests.
SYNCSOURCES
BACKEND_DEFINES
BACKEND_CPPFLAGS
+GNOMEBLUETOOTH_CFLAGS
+GNOMEBLUETOOTH_LIBS
+GNOMEBLUETOOTH_DIR
+ENABLE_GNOME_BLUETOOTH_PANEL_TRUE
+ENABLE_GNOME_BLUETOOTH_PANEL_FALSE
ADDRESSBOOK_CFLAGS
ADDRESSBOOK_LIBS
EPACKAGE_CFLAGS
EBOOK_LIBS
ENABLE_ECAL_TRUE
ENABLE_ECAL_FALSE
+LIBICAL_AVAILABLE_CFLAGS
+LIBICAL_AVAILABLE_LIBS
FILE_CFLAGS
FILE_LIBS
MCALB_CFLAGS
GTHREAD_LIBS
GOBJECT_CFLAGS
GOBJECT_LIBS
+GLIB216_CFLAGS
+GLIB216_LIBS
+NSS_CFLAGS
+NSS_LIBS
ENABLE_MODULES_TRUE
ENABLE_MODULES_FALSE
SYNCEVOLUTION_LDADD
CCC
SYNTHESIS_CFLAGS
SYNTHESIS_LIBS
+GNOMEBLUETOOTH_CFLAGS
+GNOMEBLUETOOTH_LIBS
EPACKAGE_CFLAGS
EPACKAGE_LIBS
ECAL_CFLAGS
ECAL_LIBS
EBOOK_CFLAGS
EBOOK_LIBS
+LIBICAL_AVAILABLE_CFLAGS
+LIBICAL_AVAILABLE_LIBS
MCALB_CFLAGS
MCALB_LIBS
SQLITE_CFLAGS
GTHREAD_CFLAGS
GTHREAD_LIBS
GOBJECT_CFLAGS
-GOBJECT_LIBS'
+GOBJECT_LIBS
+GLIB216_CFLAGS
+GLIB216_LIBS
+NSS_CFLAGS
+NSS_LIBS'
# Initialize some variables set by options.
# 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.0beta1 to adapt to many kinds of systems.
+\`configure' configures syncevolution 1.0beta2a to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of syncevolution 1.0beta1:";;
+ short | recursive ) echo "Configuration of syncevolution 1.0beta2a:";;
esac
cat <<\_ACEOF
--enable-dbus-service enables building the dbus service executable and the
wrapper library for it
--disable-nls do not use Native Language Support
+ --enable-gnome-bluetooth-panel-plugin
+ GNOME Bluetooth panel plugin adding a "sync" button
+ for paired devices (off by default)
--enable-addressbook enable access to Mac OS X address book (default off)
--disable-ebook disable access to Evolution addressbooks (must be
used to compile without it)
C compiler flags for SYNTHESIS, overriding pkg-config
SYNTHESIS_LIBS
linker flags for SYNTHESIS, overriding pkg-config
+ GNOMEBLUETOOTH_CFLAGS
+ C compiler flags for GNOMEBLUETOOTH, overriding pkg-config
+ GNOMEBLUETOOTH_LIBS
+ linker flags for GNOMEBLUETOOTH, overriding pkg-config
EPACKAGE_CFLAGS
C compiler flags for EPACKAGE, overriding pkg-config
EPACKAGE_LIBS
EBOOK_CFLAGS
C compiler flags for EBOOK, overriding pkg-config
EBOOK_LIBS linker flags for EBOOK, overriding pkg-config
+ LIBICAL_AVAILABLE_CFLAGS
+ C compiler flags for LIBICAL_AVAILABLE, overriding pkg-config
+ LIBICAL_AVAILABLE_LIBS
+ linker flags for LIBICAL_AVAILABLE, overriding pkg-config
MCALB_CFLAGS
C compiler flags for MCALB, overriding pkg-config
MCALB_LIBS linker flags for MCALB, overriding pkg-config
C compiler flags for GOBJECT, overriding pkg-config
GOBJECT_LIBS
linker flags for GOBJECT, overriding pkg-config
+ GLIB216_CFLAGS
+ C compiler flags for GLIB216, overriding pkg-config
+ GLIB216_LIBS
+ linker flags for GLIB216, overriding pkg-config
+ NSS_CFLAGS C compiler flags for NSS, overriding pkg-config
+ NSS_LIBS linker flags for NSS, overriding pkg-config
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-syncevolution configure 1.0beta1
+syncevolution configure 1.0beta2a
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
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.0beta1, which was
+It was created by syncevolution $as_me 1.0beta2a, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='syncevolution'
- VERSION='1.0beta1'
+ VERSION='1.0beta2a'
cat >>confdefs.h <<_ACEOF
fi
-if test "$have_bluetooth"; then
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
- CFLAGS_old="$CFLAGS"
- CFLAGS="$CPPFLAGS $BLUEZ_CFLAGS"
- # test in this order:
- # - recent libbluetooth (no _safe variant, base function has bufsize)
- # - intermediate with _safe
- # - else assume old-style (no bufsize, no _safe)
- #
- # The source code checks the signature both by via pointer assignment and calling
- # it (better safe than sorry). One these should fail if the signature is not right.
- cat >conftest.$ac_ext <<_ACEOF
-#include <bluetooth/sdp.h>
- #include <bluetooth/sdp_lib.h>
- sdp_record_t *(*extract_pdu)(const uint8_t *pdata, int bufsize, int *scanned) =
- sdp_extract_pdu;
- void foo(void) {
- uint8_t *pdata = NULL;
- int scanned;
- sdp_extract_pdu(pdata, 100, &scanned);
- }
-
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
- (eval "$ac_compile") 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest.$ac_objext; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_BLUEZ_BUFSIZE 1
-_ACEOF
-
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- cat >conftest.$ac_ext <<_ACEOF
-#include <bluetooth/sdp.h>
- #include <bluetooth/sdp_lib.h>
- sdp_record_t *(*extract_pdu)(const uint8_t *pdata, int bufsize, int *scanned) =
- sdp_extract_pdu_safe;
- void foo(void) {
- uint8_t *pdata = NULL;
- int scanned;
- sdp_extract_pdu_safe(pdata, 100, &scanned);
- }
-
-_ACEOF
-rm -f conftest.$ac_objext
-if { (ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
- (eval "$ac_compile") 2>conftest.er1
- ac_status=$?
- grep -v '^ *+' conftest.er1 >conftest.err
- rm -f conftest.er1
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- (exit $ac_status); } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest.$ac_objext; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_BLUEZ_SAFE 1
-_ACEOF
-
-else
- echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- CFLAGS="$CFLAGS_old"
-fi
-
-
if test ! "$TRANSPORT" &&
test "$libsoup_disabled" != "yes" &&
test "$libcurl_disabled" != "yes" &&
if test $enable_gui != "no"; then
gui_modules="glib-2.0 dbus-glib-1 >= 0.60 gtk+-2.0 libglade-2.0 gio-2.0"
if test $enable_gui == "moblin"; then
- gui_modules="$guimodules mx-gtk-1.0"
cat >>confdefs.h <<\_ACEOF
#define USE_MOBLIN_UX 1
_ACEOF
fi
+ if test $enable_gui == "moblin" -o $enable_gui == "all"; then
+ gui_modules="$guimodules mx-gtk-1.0"
+ fi
pkg_failed=no
BACKEND_CPPFLAGS="$SYNTHESIS_CFLAGS $EPACKAGE_CFLAGS $EBOOK_CFLAGS $ECAL_CFLAGS $GLIB_CFLAGS $BOOST_CPPFLAGS"
+# GNOME Bluetooth Panel plugin
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GNOMEBLUETOOTH" >&5
+echo $ECHO_N "checking for GNOMEBLUETOOTH... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GNOMEBLUETOOTH_CFLAGS"; then
+ pkg_cv_GNOMEBLUETOOTH_CFLAGS="$GNOMEBLUETOOTH_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gnome-bluetooth-1.0 >= 2.27.6\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gnome-bluetooth-1.0 >= 2.27.6") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GNOMEBLUETOOTH_CFLAGS=`$PKG_CONFIG --cflags "gnome-bluetooth-1.0 >= 2.27.6" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GNOMEBLUETOOTH_LIBS"; then
+ pkg_cv_GNOMEBLUETOOTH_LIBS="$GNOMEBLUETOOTH_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gnome-bluetooth-1.0 >= 2.27.6\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gnome-bluetooth-1.0 >= 2.27.6") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GNOMEBLUETOOTH_LIBS=`$PKG_CONFIG --libs "gnome-bluetooth-1.0 >= 2.27.6" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GNOMEBLUETOOTH_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gnome-bluetooth-1.0 >= 2.27.6"`
+ else
+ GNOMEBLUETOOTH_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gnome-bluetooth-1.0 >= 2.27.6"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GNOMEBLUETOOTH_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ have_gbt="no"
+elif test $pkg_failed = untried; then
+ have_gbt="no"
+else
+ GNOMEBLUETOOTH_CFLAGS=$pkg_cv_GNOMEBLUETOOTH_CFLAGS
+ GNOMEBLUETOOTH_LIBS=$pkg_cv_GNOMEBLUETOOTH_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ have_gbt="yes"
+ GNOMEBLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0 2>/dev/null`/gnome-bluetooth
+fi
+
+
+
+# Check whether --enable-gnome-bluetooth-panel-plugin was given.
+if test "${enable_gnome_bluetooth_panel_plugin+set}" = set; then
+ enableval=$enable_gnome_bluetooth_panel_plugin; enable_gnome_bluetooth_panel="$enableval"
+else
+ enable_gnome_bluetooth_panel="no"
+
+fi
+
+if test "$enable_gnome_bluetooth_panel" = "yes"; then
+ test "$have_gbt" = "yes" || { { echo "$as_me:$LINENO: error: --enable-gnome-bluetooth-panel requires
+ pkg-config information for gnome-bluetooth-1.0 >= 2.27.6 which was not found" >&5
+echo "$as_me: error: --enable-gnome-bluetooth-panel requires
+ pkg-config information for gnome-bluetooth-1.0 >= 2.27.6 which was not found" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_files="$ac_config_files src/gnome-bluetooth/Makefile"
+
+ if test "$have_gbt" = "yes" && test "$enable_gnome_bluetooth_panel" = "yes"; then
+ ENABLE_GNOME_BLUETOOTH_PANEL_TRUE=
+ ENABLE_GNOME_BLUETOOTH_PANEL_FALSE='#'
+else
+ ENABLE_GNOME_BLUETOOTH_PANEL_TRUE='#'
+ ENABLE_GNOME_BLUETOOTH_PANEL_FALSE=
+fi
+
+
+
# vvvvvvvvvvvvvv src/backends/addressbook/configure-sub.in vvvvvvvvvvvvvv
ADDRESSBOOK_CFLAGS=
ECAL_LIBS=
fi
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for LIBICAL_AVAILABLE" >&5
+echo $ECHO_N "checking for LIBICAL_AVAILABLE... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+ if test -n "$LIBICAL_AVAILABLE_CFLAGS"; then
+ pkg_cv_LIBICAL_AVAILABLE_CFLAGS="$LIBICAL_AVAILABLE_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libical >= 0.43\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libical >= 0.43") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_LIBICAL_AVAILABLE_CFLAGS=`$PKG_CONFIG --cflags "libical >= 0.43" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+ if test -n "$LIBICAL_AVAILABLE_LIBS"; then
+ pkg_cv_LIBICAL_AVAILABLE_LIBS="$LIBICAL_AVAILABLE_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"libical >= 0.43\"") >&5
+ ($PKG_CONFIG --exists --print-errors "libical >= 0.43") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_LIBICAL_AVAILABLE_LIBS=`$PKG_CONFIG --libs "libical >= 0.43" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LIBICAL_AVAILABLE_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "libical >= 0.43"`
+ else
+ LIBICAL_AVAILABLE_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "libical >= 0.43"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBICAL_AVAILABLE_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ pass
+elif test $pkg_failed = untried; then
+ pass
+else
+ LIBICAL_AVAILABLE_CFLAGS=$pkg_cv_LIBICAL_AVAILABLE_CFLAGS
+ LIBICAL_AVAILABLE_LIBS=$pkg_cv_LIBICAL_AVAILABLE_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBICAL_R 1
+_ACEOF
+
+fi
+
if test "$enable_evo" = "yes"; then
need_glib="yes"
if test "$EDSFOUND" = "yes"; then
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 12330 "configure"' > conftest.$ac_ext
+ echo '#line 12444 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14435: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14549: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14439: \$? = $ac_status" >&5
+ echo "$as_me:14553: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14725: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14839: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14729: \$? = $ac_status" >&5
+ echo "$as_me:14843: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14829: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14943: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:14833: \$? = $ac_status" >&5
+ echo "$as_me:14947: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 17206 "configure"
+#line 17320 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 17306 "configure"
+#line 17420 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:19707: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:19821: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:19711: \$? = $ac_status" >&5
+ echo "$as_me:19825: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:19811: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:19925: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:19815: \$? = $ac_status" >&5
+ echo "$as_me:19929: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:21409: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:21523: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:21413: \$? = $ac_status" >&5
+ echo "$as_me:21527: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:21513: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:21627: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:21517: \$? = $ac_status" >&5
+ echo "$as_me:21631: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:23733: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:23847: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:23737: \$? = $ac_status" >&5
+ echo "$as_me:23851: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:24023: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:24137: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:24027: \$? = $ac_status" >&5
+ echo "$as_me:24141: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:24127: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:24241: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:24131: \$? = $ac_status" >&5
+ echo "$as_me:24245: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
BACKEND_CPPFLAGS="$BACKEND_CPPFLAGS $GLIB_CFLAGS $GTHREAD_CFLAGS $GOBJECT_CFLAGS"
fi
+# determine from where we can get a SHA-256 implementation
+have_sha="no"
+if test "$GLIBFOUND" = "yes"; then
+ # only use glib if we need it anyway, also has to be at lease 2.16
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GLIB216" >&5
+echo $ECHO_N "checking for GLIB216... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GLIB216_CFLAGS"; then
+ pkg_cv_GLIB216_CFLAGS="$GLIB216_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.16\"") >&5
+ ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.16") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GLIB216_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.16" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GLIB216_LIBS"; then
+ pkg_cv_GLIB216_LIBS="$GLIB216_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.16\"") >&5
+ ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.16") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GLIB216_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.16" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GLIB216_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "glib-2.0 >= 2.16"`
+ else
+ GLIB216_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "glib-2.0 >= 2.16"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GLIB216_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ true
+elif test $pkg_failed = untried; then
+ true
+else
+ GLIB216_CFLAGS=$pkg_cv_GLIB216_CFLAGS
+ GLIB216_LIBS=$pkg_cv_GLIB216_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_SHA256 1
+_ACEOF
+
+ have_sha="glib"
+fi
+fi
+if test "$have_sha" = "no"; then
+ # Fallback is Mozilla NSS. In contrast to libgcrypt it has a .pc
+ # file and a simple API.
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for NSS" >&5
+echo $ECHO_N "checking for NSS... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+ if test -n "$NSS_CFLAGS"; then
+ pkg_cv_NSS_CFLAGS="$NSS_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"\"nss\"\"") >&5
+ ($PKG_CONFIG --exists --print-errors ""nss"") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_NSS_CFLAGS=`$PKG_CONFIG --cflags ""nss"" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+ if test -n "$NSS_LIBS"; then
+ pkg_cv_NSS_LIBS="$NSS_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"\"nss\"\"") >&5
+ ($PKG_CONFIG --exists --print-errors ""nss"") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_NSS_LIBS=`$PKG_CONFIG --libs ""nss"" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ NSS_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors ""nss""`
+ else
+ NSS_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors ""nss""`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$NSS_PKG_ERRORS" >&5
+
+ { { echo "$as_me:$LINENO: error: Package requirements (\"nss\") were not met:
+
+$NSS_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables NSS_CFLAGS
+and NSS_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+" >&5
+echo "$as_me: error: Package requirements (\"nss\") were not met:
+
+$NSS_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables NSS_CFLAGS
+and NSS_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+" >&2;}
+ { (exit 1); exit 1; }; }
+elif test $pkg_failed = untried; then
+ { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables NSS_CFLAGS
+and NSS_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details." >&5
+echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables NSS_CFLAGS
+and NSS_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ NSS_CFLAGS=$pkg_cv_NSS_CFLAGS
+ NSS_LIBS=$pkg_cv_NSS_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_SHA256 2
+_ACEOF
+
+ have_sha="nss"
+fi
+fi
+
if test "$enable_shared" == "yes"; then
ENABLE_MODULES_TRUE=
ENABLE_MODULES_FALSE='#'
fi
-ac_config_files="$ac_config_files Makefile src/dbus/interfaces/Makefile src/gdbus/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc"
+ac_config_files="$ac_config_files Makefile src/dbus/interfaces/Makefile src/gdbus/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/syncevo/configs/Makefile src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${ENABLE_GNOME_BLUETOOTH_PANEL_TRUE}" && test -z "${ENABLE_GNOME_BLUETOOTH_PANEL_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"ENABLE_GNOME_BLUETOOTH_PANEL\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"ENABLE_GNOME_BLUETOOTH_PANEL\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
if test -z "${ENABLE_ECAL_TRUE}" && test -z "${ENABLE_ECAL_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"ENABLE_ECAL\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
# 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.0beta1, which was
+This file was extended by syncevolution $as_me 1.0beta2a, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-syncevolution config.status 1.0beta1
+syncevolution config.status 1.0beta2a
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
"depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
"default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;;
+ "src/gnome-bluetooth/Makefile") CONFIG_FILES="$CONFIG_FILES src/gnome-bluetooth/Makefile" ;;
"src/backends/addressbook/Makefile") CONFIG_FILES="$CONFIG_FILES src/backends/addressbook/Makefile" ;;
"src/backends/evolution/Makefile") CONFIG_FILES="$CONFIG_FILES src/backends/evolution/Makefile" ;;
"src/backends/file/Makefile") CONFIG_FILES="$CONFIG_FILES src/backends/file/Makefile" ;;
"src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
"src/syncevo/Makefile") CONFIG_FILES="$CONFIG_FILES src/syncevo/Makefile" ;;
"src/syncevo/syncevolution.pc") CONFIG_FILES="$CONFIG_FILES src/syncevo/syncevolution.pc" ;;
+ "src/syncevo/configs/Makefile") CONFIG_FILES="$CONFIG_FILES src/syncevo/configs/Makefile" ;;
"src/gtk-ui/Makefile") CONFIG_FILES="$CONFIG_FILES src/gtk-ui/Makefile" ;;
"po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
SYNCSOURCES!$SYNCSOURCES$ac_delim
BACKEND_DEFINES!$BACKEND_DEFINES$ac_delim
BACKEND_CPPFLAGS!$BACKEND_CPPFLAGS$ac_delim
-ADDRESSBOOK_CFLAGS!$ADDRESSBOOK_CFLAGS$ac_delim
-ADDRESSBOOK_LIBS!$ADDRESSBOOK_LIBS$ac_delim
-EPACKAGE_CFLAGS!$EPACKAGE_CFLAGS$ac_delim
-EPACKAGE_LIBS!$EPACKAGE_LIBS$ac_delim
-ECAL_CFLAGS!$ECAL_CFLAGS$ac_delim
+GNOMEBLUETOOTH_CFLAGS!$GNOMEBLUETOOTH_CFLAGS$ac_delim
+GNOMEBLUETOOTH_LIBS!$GNOMEBLUETOOTH_LIBS$ac_delim
+GNOMEBLUETOOTH_DIR!$GNOMEBLUETOOTH_DIR$ac_delim
+ENABLE_GNOME_BLUETOOTH_PANEL_TRUE!$ENABLE_GNOME_BLUETOOTH_PANEL_TRUE$ac_delim
+ENABLE_GNOME_BLUETOOTH_PANEL_FALSE!$ENABLE_GNOME_BLUETOOTH_PANEL_FALSE$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
cat >conf$$subs.sed <<_ACEOF
+ADDRESSBOOK_CFLAGS!$ADDRESSBOOK_CFLAGS$ac_delim
+ADDRESSBOOK_LIBS!$ADDRESSBOOK_LIBS$ac_delim
+EPACKAGE_CFLAGS!$EPACKAGE_CFLAGS$ac_delim
+EPACKAGE_LIBS!$EPACKAGE_LIBS$ac_delim
+ECAL_CFLAGS!$ECAL_CFLAGS$ac_delim
ECAL_LIBS!$ECAL_LIBS$ac_delim
EBOOK_CFLAGS!$EBOOK_CFLAGS$ac_delim
EBOOK_LIBS!$EBOOK_LIBS$ac_delim
ENABLE_ECAL_TRUE!$ENABLE_ECAL_TRUE$ac_delim
ENABLE_ECAL_FALSE!$ENABLE_ECAL_FALSE$ac_delim
+LIBICAL_AVAILABLE_CFLAGS!$LIBICAL_AVAILABLE_CFLAGS$ac_delim
+LIBICAL_AVAILABLE_LIBS!$LIBICAL_AVAILABLE_LIBS$ac_delim
FILE_CFLAGS!$FILE_CFLAGS$ac_delim
FILE_LIBS!$FILE_LIBS$ac_delim
MCALB_CFLAGS!$MCALB_CFLAGS$ac_delim
GTHREAD_LIBS!$GTHREAD_LIBS$ac_delim
GOBJECT_CFLAGS!$GOBJECT_CFLAGS$ac_delim
GOBJECT_LIBS!$GOBJECT_LIBS$ac_delim
+GLIB216_CFLAGS!$GLIB216_CFLAGS$ac_delim
+GLIB216_LIBS!$GLIB216_LIBS$ac_delim
+NSS_CFLAGS!$NSS_CFLAGS$ac_delim
+NSS_LIBS!$NSS_LIBS$ac_delim
ENABLE_MODULES_TRUE!$ENABLE_MODULES_TRUE$ac_delim
ENABLE_MODULES_FALSE!$ENABLE_MODULES_FALSE$ac_delim
SYNCEVOLUTION_LDADD!$SYNCEVOLUTION_LDADD$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 49; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 60; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
echo "DBus service: $enable_dbus_service"
echo "UI (DBus client): $enable_gui"
echo "Bluetooth transport: $have_bluetooth"
+echo "GNOME Bluetooth panel plugin: $enable_gnome_bluetooth_panel"
+echo "SHA-256: $have_sha"
echo
BACKEND_CPPFLAGS="$BACKEND_CPPFLAGS $GLIB_CFLAGS $GTHREAD_CFLAGS $GOBJECT_CFLAGS"
fi
+# determine from where we can get a SHA-256 implementation
+have_sha="no"
+if test "$GLIBFOUND" = "yes"; then
+ # only use glib if we need it anyway, also has to be at lease 2.16
+ PKG_CHECK_MODULES(GLIB216, [glib-2.0 >= 2.16],
+ [AC_DEFINE(USE_SHA256, 1, [choose implementation of SHA-256])
+ have_sha="glib"],
+ [true])
+fi
+if test "$have_sha" = "no"; then
+ # Fallback is Mozilla NSS. In contrast to libgcrypt it has a .pc
+ # file and a simple API.
+ PKG_CHECK_MODULES(NSS, "nss",
+ [AC_DEFINE(USE_SHA256, 2, [choose implementation of SHA-256])
+ have_sha="nss"])
+fi
+
dnl figure out whether we link all code statically or as modules
AM_CONDITIONAL([ENABLE_MODULES], [test "$enable_shared" == "yes"])
if test "$enable_shared" == "yes"; then
AC_SUBST(docdir)
fi
-AC_CONFIG_FILES(Makefile src/dbus/interfaces/Makefile src/gdbus/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc)
+AC_CONFIG_FILES(Makefile src/dbus/interfaces/Makefile src/gdbus/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/syncevo/configs/Makefile src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc)
AC_OUTPUT
echo
echo "DBus service: $enable_dbus_service"
echo "UI (DBus client): $enable_gui"
echo "Bluetooth transport: $have_bluetooth"
+echo "GNOME Bluetooth panel plugin: $enable_gnome_bluetooth_panel"
+echo "SHA-256: $have_sha"
echo
# Debian packages. For prereleases (beta, alpha),
# set it to something like "0.9.2+" and the AC_INIT
# VERSION to 1.0beta1 to produce 0.9.2+1.0beta1.
-AC_INIT([syncevolution], [1.0beta1])
+AC_INIT([syncevolution], [1.0beta2a])
STABLE_VERSION=0.9.2+
AC_SUBST(STABLE_VERSION)
AM_CONDITIONAL([ENABLE_OBEX], [test "$have_obex" = "yes" && test "$enable_bluetooth" = "yes"])
AM_CONDITIONAL([ENABLE_BLUETOOTH], [test "$have_bluetooth" = "yes" && test "$enable_bluetooth" = "yes"])
-if test "$have_bluetooth"; then
- AC_LANG(C)
- CFLAGS_old="$CFLAGS"
- CFLAGS="$CPPFLAGS $BLUEZ_CFLAGS"
- # test in this order:
- # - recent libbluetooth (no _safe variant, base function has bufsize)
- # - intermediate with _safe
- # - else assume old-style (no bufsize, no _safe)
- #
- # The source code checks the signature both by via pointer assignment and calling
- # it (better safe than sorry). One these should fail if the signature is not right.
- AC_COMPILE_IFELSE([#include <bluetooth/sdp.h>
- #include <bluetooth/sdp_lib.h>
- sdp_record_t *(*extract_pdu)(const uint8_t *pdata, int bufsize, int *scanned) =
- sdp_extract_pdu;
- void foo(void) {
- uint8_t *pdata = NULL;
- int scanned;
- sdp_extract_pdu(pdata, 100, &scanned);
- }
- ],
- AC_DEFINE(HAVE_BLUEZ_BUFSIZE, 1, [base libbluetooth functions accept bufsize parameter]),
- AC_COMPILE_IFELSE([#include <bluetooth/sdp.h>
- #include <bluetooth/sdp_lib.h>
- sdp_record_t *(*extract_pdu)(const uint8_t *pdata, int bufsize, int *scanned) =
- sdp_extract_pdu_safe;
- void foo(void) {
- uint8_t *pdata = NULL;
- int scanned;
- sdp_extract_pdu_safe(pdata, 100, &scanned);
- }
- ],
- AC_DEFINE(HAVE_BLUEZ_SAFE, 1, [libbluetooth has _safe variants])))
- CFLAGS="$CFLAGS_old"
-fi
-
-
if test ! "$TRANSPORT" &&
test "$libsoup_disabled" != "yes" &&
test "$libcurl_disabled" != "yes" &&
if test $enable_gui != "no"; then
gui_modules="glib-2.0 dbus-glib-1 >= 0.60 gtk+-2.0 libglade-2.0 gio-2.0"
if test $enable_gui == "moblin"; then
- gui_modules="$guimodules mx-gtk-1.0"
AC_DEFINE(USE_MOBLIN_UX, 1, [Use Moblin UI widgets])
fi
+ if test $enable_gui == "moblin" -o $enable_gui == "all"; then
+ gui_modules="$guimodules mx-gtk-1.0"
+ fi
PKG_CHECK_MODULES(UNIQUE, unique-1.0,
have_unique="yes",
BACKEND_CPPFLAGS="$SYNTHESIS_CFLAGS $EPACKAGE_CFLAGS $EBOOK_CFLAGS $ECAL_CFLAGS $GLIB_CFLAGS $BOOST_CPPFLAGS"
AC_SUBST(BACKEND_CPPFLAGS)
+# GNOME Bluetooth Panel plugin
+PKG_CHECK_MODULES(GNOMEBLUETOOTH, [gnome-bluetooth-1.0 >= 2.27.6],
+ [have_gbt="yes"
+ GNOMEBLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0 2>/dev/null`/gnome-bluetooth],
+ have_gbt="no")
+AC_SUBST(GNOMEBLUETOOTH_CFLAGS)
+AC_SUBST(GNOMEBLUETOOTH_DIR)
+
+AC_ARG_ENABLE(gnome-bluetooth-panel-plugin,
+ AC_HELP_STRING([--enable-gnome-bluetooth-panel-plugin],
+ [GNOME Bluetooth panel plugin adding a "sync" button for paired devices (off by default)]),
+ [enable_gnome_bluetooth_panel="$enableval"],
+ [enable_gnome_bluetooth_panel="no"]
+ )
+if test "$enable_gnome_bluetooth_panel" = "yes"; then
+ test "$have_gbt" = "yes" || AC_MSG_ERROR([--enable-gnome-bluetooth-panel requires
+ pkg-config information for gnome-bluetooth-1.0 >= 2.27.6 which was not found])
+fi
+AC_CONFIG_FILES(src/gnome-bluetooth/Makefile)
+AM_CONDITIONAL([ENABLE_GNOME_BLUETOOTH_PANEL], [test "$have_gbt" = "yes" && test "$enable_gnome_bluetooth_panel" = "yes"])
+
+
dnl src/backends/*/configure-sub.in and configure-post.in follow
# Debian packages. For prereleases (beta, alpha),
# set it to something like "0.9.2+" and the AC_INIT
# VERSION to 1.0beta1 to produce 0.9.2+1.0beta1.
-AC_INIT([syncevolution], [1.0beta1])
+AC_INIT([syncevolution], [1.0beta2a])
STABLE_VERSION=0.9.2+
AC_SUBST(STABLE_VERSION)
AM_CONDITIONAL([ENABLE_OBEX], [test "$have_obex" = "yes" && test "$enable_bluetooth" = "yes"])
AM_CONDITIONAL([ENABLE_BLUETOOTH], [test "$have_bluetooth" = "yes" && test "$enable_bluetooth" = "yes"])
-if test "$have_bluetooth"; then
- AC_LANG(C)
- CFLAGS_old="$CFLAGS"
- CFLAGS="$CPPFLAGS $BLUEZ_CFLAGS"
- # test in this order:
- # - recent libbluetooth (no _safe variant, base function has bufsize)
- # - intermediate with _safe
- # - else assume old-style (no bufsize, no _safe)
- #
- # The source code checks the signature both by via pointer assignment and calling
- # it (better safe than sorry). One these should fail if the signature is not right.
- AC_COMPILE_IFELSE([#include <bluetooth/sdp.h>
- #include <bluetooth/sdp_lib.h>
- sdp_record_t *(*extract_pdu)(const uint8_t *pdata, int bufsize, int *scanned) =
- sdp_extract_pdu;
- void foo(void) {
- uint8_t *pdata = NULL;
- int scanned;
- sdp_extract_pdu(pdata, 100, &scanned);
- }
- ],
- AC_DEFINE(HAVE_BLUEZ_BUFSIZE, 1, [base libbluetooth functions accept bufsize parameter]),
- AC_COMPILE_IFELSE([#include <bluetooth/sdp.h>
- #include <bluetooth/sdp_lib.h>
- sdp_record_t *(*extract_pdu)(const uint8_t *pdata, int bufsize, int *scanned) =
- sdp_extract_pdu_safe;
- void foo(void) {
- uint8_t *pdata = NULL;
- int scanned;
- sdp_extract_pdu_safe(pdata, 100, &scanned);
- }
- ],
- AC_DEFINE(HAVE_BLUEZ_SAFE, 1, [libbluetooth has _safe variants])))
- CFLAGS="$CFLAGS_old"
-fi
-
-
if test ! "$TRANSPORT" &&
test "$libsoup_disabled" != "yes" &&
test "$libcurl_disabled" != "yes" &&
if test $enable_gui != "no"; then
gui_modules="glib-2.0 dbus-glib-1 >= 0.60 gtk+-2.0 libglade-2.0 gio-2.0"
if test $enable_gui == "moblin"; then
- gui_modules="$guimodules mx-gtk-1.0"
AC_DEFINE(USE_MOBLIN_UX, 1, [Use Moblin UI widgets])
fi
+ if test $enable_gui == "moblin" -o $enable_gui == "all"; then
+ gui_modules="$guimodules mx-gtk-1.0"
+ fi
PKG_CHECK_MODULES(UNIQUE, unique-1.0,
have_unique="yes",
BACKEND_CPPFLAGS="$SYNTHESIS_CFLAGS $EPACKAGE_CFLAGS $EBOOK_CFLAGS $ECAL_CFLAGS $GLIB_CFLAGS $BOOST_CPPFLAGS"
AC_SUBST(BACKEND_CPPFLAGS)
+# GNOME Bluetooth Panel plugin
+PKG_CHECK_MODULES(GNOMEBLUETOOTH, [gnome-bluetooth-1.0 >= 2.27.6],
+ [have_gbt="yes"
+ GNOMEBLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0 2>/dev/null`/gnome-bluetooth],
+ have_gbt="no")
+AC_SUBST(GNOMEBLUETOOTH_CFLAGS)
+AC_SUBST(GNOMEBLUETOOTH_DIR)
+
+AC_ARG_ENABLE(gnome-bluetooth-panel-plugin,
+ AC_HELP_STRING([--enable-gnome-bluetooth-panel-plugin],
+ [GNOME Bluetooth panel plugin adding a "sync" button for paired devices (off by default)]),
+ [enable_gnome_bluetooth_panel="$enableval"],
+ [enable_gnome_bluetooth_panel="no"]
+ )
+if test "$enable_gnome_bluetooth_panel" = "yes"; then
+ test "$have_gbt" = "yes" || AC_MSG_ERROR([--enable-gnome-bluetooth-panel requires
+ pkg-config information for gnome-bluetooth-1.0 >= 2.27.6 which was not found])
+fi
+AC_CONFIG_FILES(src/gnome-bluetooth/Makefile)
+AM_CONDITIONAL([ENABLE_GNOME_BLUETOOTH_PANEL], [test "$have_gbt" = "yes" && test "$enable_gnome_bluetooth_panel" = "yes"])
+
+
dnl src/backends/*/configure-sub.in and configure-post.in follow
# vvvvvvvvvvvvvv src/backends/addressbook/configure-sub.in vvvvvvvvvvvvvv
dnl -*- mode: Autoconf; -*-
ECAL_LIBS=
fi
+PKG_CHECK_MODULES(LIBICAL_AVAILABLE,
+ libical >= 0.43,
+ AC_DEFINE(HAVE_LIBICAL_R, 1, [have recent enough libical with _r variants]),
+ pass)
+
if test "$enable_evo" = "yes"; then
need_glib="yes"
if test "$EDSFOUND" = "yes"; then
BACKEND_CPPFLAGS="$BACKEND_CPPFLAGS $GLIB_CFLAGS $GTHREAD_CFLAGS $GOBJECT_CFLAGS"
fi
+# determine from where we can get a SHA-256 implementation
+have_sha="no"
+if test "$GLIBFOUND" = "yes"; then
+ # only use glib if we need it anyway, also has to be at lease 2.16
+ PKG_CHECK_MODULES(GLIB216, [glib-2.0 >= 2.16],
+ [AC_DEFINE(USE_SHA256, 1, [choose implementation of SHA-256])
+ have_sha="glib"],
+ [true])
+fi
+if test "$have_sha" = "no"; then
+ # Fallback is Mozilla NSS. In contrast to libgcrypt it has a .pc
+ # file and a simple API.
+ PKG_CHECK_MODULES(NSS, "nss",
+ [AC_DEFINE(USE_SHA256, 2, [choose implementation of SHA-256])
+ have_sha="nss"])
+fi
+
dnl figure out whether we link all code statically or as modules
AM_CONDITIONAL([ENABLE_MODULES], [test "$enable_shared" == "yes"])
if test "$enable_shared" == "yes"; then
AC_SUBST(docdir)
fi
-AC_CONFIG_FILES(Makefile src/dbus/interfaces/Makefile src/gdbus/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc)
+AC_CONFIG_FILES(Makefile src/dbus/interfaces/Makefile src/gdbus/Makefile src/dbus/Makefile src/Makefile src/syncevo/Makefile src/syncevo/syncevolution.pc src/syncevo/configs/Makefile src/gtk-ui/Makefile po/Makefile.in test/Makefile src/dbus/syncevo-dbus.pc)
AC_OUTPUT
echo
echo "DBus service: $enable_dbus_service"
echo "UI (DBus client): $enable_gui"
echo "Bluetooth transport: $have_bluetooth"
+echo "GNOME Bluetooth panel plugin: $enable_gnome_bluetooth_panel"
+echo "SHA-256: $have_sha"
echo
src/gtk-ui/sync.desktop.in
src/gtk-ui/sync-gtk.desktop.in
src/gtk-ui/sync-config-widget.c
+src/gnome-bluetooth/syncevolution.c
msgstr ""
"Project-Id-Version: syncevolution\n"
"Report-Msgid-Bugs-To: http://moblin.org/projects/syncevolution\n"
-"POT-Creation-Date: 2009-11-19 18:24+0000\n"
-"PO-Revision-Date: 2009-11-24 15:33-0800\n"
-"Last-Translator: Tomás Galicia <tomas.galicia@intel.com>\n"
+"POT-Creation-Date: 2010-02-12 00:01+0000\n"
+"PO-Revision-Date: 2010-02-24 13:28+0100\n"
+"Last-Translator: Lorenzo <lorenzo.gennaro@ptiglobal.net>\n"
"Language-Team: Italian <tp@lists.linux.it>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
# (ndt) titolo finestra
#. TRANSLATORS: this is the application name that may be used by e.g.
#. the windowmanager
-#: ../src/gtk-ui/main.c:31
-#: ../src/gtk-ui/ui.glade.h:28
+#: ../src/gtk-ui/main.c:40
+#: ../src/gtk-ui/ui.glade.h:36
#: ../src/gtk-ui/sync.desktop.in.h:1
+#: ../src/gnome-bluetooth/syncevolution.c:112
msgid "Sync"
msgstr "Sincronizzazione"
-#: ../src/gtk-ui/sync-ui.c:259
-msgid "Addressbook"
-msgstr "Rubrica"
+#: ../src/gtk-ui/sync-ui.c:234
+msgid "Contacts"
+msgstr "Contatti"
-#: ../src/gtk-ui/sync-ui.c:261
-msgid "Calendar"
-msgstr "Calendario"
-
-#: ../src/gtk-ui/sync-ui.c:263
-msgid "Todo"
-msgstr "Attività"
-
-#: ../src/gtk-ui/sync-ui.c:265
-msgid "Memo"
-msgstr "Memo"
-
-#: ../src/gtk-ui/sync-ui.c:320
-msgid "Failed to save current service in GConf configuration system"
-msgstr "Salvataggio del servizio attuale nel sistema di configurazione GConf non riuscito"
+#: ../src/gtk-ui/sync-ui.c:236
+msgid "Appointments"
+msgstr "Appuntamenti"
-#: ../src/gtk-ui/sync-ui.c:331
-msgid "Failed to save service configuration to SyncEvolution"
-msgstr "Salvataggio della configurazione del servizio in SyncEvolution non riuscito"
-
-#: ../src/gtk-ui/sync-ui.c:416
-msgid "Failed to get service configuration from SyncEvolution"
-msgstr "Recupero della configurazione del servizio da SyncEvolution non riuscito"
-
-#: ../src/gtk-ui/sync-ui.c:480
-msgid "Failed to remove service configuration from SyncEvolution"
-msgstr "Rimozione della configurazione del servizio da SyncEvolution non riuscita"
-
-#: ../src/gtk-ui/sync-ui.c:600
-msgid "Service must have a name and server URL"
-msgstr "Il servizio deve avere un nome e un indirizzo del server"
+#: ../src/gtk-ui/sync-ui.c:238
+#: ../src/gtk-ui/ui.glade.h:38
+msgid "Tasks"
+msgstr "Compiti"
-#. sync is no longer in progress for some reason
-#: ../src/gtk-ui/sync-ui.c:676
-msgid "Failed to cancel: sync was no longer in progress"
-msgstr "Annullamento non riuscito: la sincronizzazione non era più in corso"
+#: ../src/gtk-ui/sync-ui.c:240
+msgid "Notes"
+msgstr "Note"
-#: ../src/gtk-ui/sync-ui.c:680
-msgid "Failed to cancel sync"
-msgstr "Annullamento sincronizzazione non riuscito"
+#. TRANSLATORS: This is a "combination source" for syncing with devices
+#. * that combine appointments and tasks. the name should match the ones
+#. * used for calendar and todo above
+#: ../src/gtk-ui/sync-ui.c:245
+msgid "Appointments & Tasks"
+msgstr "Appuntamenti e compiti"
-#: ../src/gtk-ui/sync-ui.c:684
-msgid "Canceling sync"
-msgstr "Annullamento sincronizzazione"
-
-#: ../src/gtk-ui/sync-ui.c:698
-msgid "Trying to cancel sync"
-msgstr "Tentativo di annullare la sincronizzazione"
+#: ../src/gtk-ui/sync-ui.c:317
+msgid "Starting sync"
+msgstr "Avvio sincronizzazione"
-#: ../src/gtk-ui/sync-ui.c:705
+#. TRANSLATORS: slow sync confirmation dialog message. Placeholder
+#. * is service/device name
+#: ../src/gtk-ui/sync-ui.c:355
#, c-format
-msgid "Do you want to delete all local data and replace it with data from %s? This is not usually advised."
-msgstr "Eliminare i dati locali e sostituirli con quelli da %s? Solitamente questo non è consigliato."
+msgid "Do you want to slow sync with %s?"
+msgstr "Vuoi effettuare la sincronizzazione lenta con %s?"
-#: ../src/gtk-ui/sync-ui.c:710
-#, c-format
-msgid "Do you want to delete all data in %s and replace it with your local data? This is not usually advised."
-msgstr "Eliminare i dati in %s e sostituirli con quelli locali? Solitamente questo non è consigliato."
+#: ../src/gtk-ui/sync-ui.c:359
+msgid "Yes, do slow sync"
+msgstr "Sì, effettua la sincronizzazione lenta"
# (ndt) pulsante
-#: ../src/gtk-ui/sync-ui.c:727
+#: ../src/gtk-ui/sync-ui.c:359
msgid "No, cancel sync"
msgstr "Annulla sincronizzazione"
+#. TRANSLATORS: confirmation dialog for refresh-from-server. Placeholder
+#. * is service/device name
+#: ../src/gtk-ui/sync-ui.c:392
+#, c-format
+msgid "Do you want to delete all local data and replace it with data from %s? This is not usually advised."
+msgstr "Eliminare i dati locali e sostituirli con quelli da %s? Solitamente questo non è consigliato."
+
# (ndt) pulsante
-#: ../src/gtk-ui/sync-ui.c:728
+#: ../src/gtk-ui/sync-ui.c:397
+#: ../src/gtk-ui/sync-ui.c:428
msgid "Yes, delete and replace"
msgstr "Elimia e sostituisci"
-#: ../src/gtk-ui/sync-ui.c:750
-msgid "No sources are enabled, not syncing"
-msgstr "Nessuna sorgente è abilitata, niente da sincronizzare"
+#: ../src/gtk-ui/sync-ui.c:397
+#: ../src/gtk-ui/sync-ui.c:428
+#: ../src/gtk-ui/sync-ui.c:1217
+msgid "No"
+msgstr "No"
-#: ../src/gtk-ui/sync-ui.c:767
-msgid "A sync is already in progress"
-msgstr "È già in corso una sincronizzazione"
+#. TRANSLATORS: confirmation dialog for refresh-from-client. Placeholder
+#. * is service/device name
+#: ../src/gtk-ui/sync-ui.c:423
+#, c-format
+msgid "Do you want to delete all data in %s and replace it with your local data? This is not usually advised."
+msgstr "Eliminare i dati in %s e sostituirli con quelli locali? Solitamente questo non è consigliato."
-#: ../src/gtk-ui/sync-ui.c:769
-msgid "Failed to start sync"
-msgstr "Avvio della sincronizzazione non riuscito"
+#: ../src/gtk-ui/sync-ui.c:455
+msgid "Trying to cancel sync"
+msgstr "Tentativo di annullare la sincronizzazione"
-#: ../src/gtk-ui/sync-ui.c:774
-msgid "Starting sync"
-msgstr "Avvio sincronizzazione"
+#: ../src/gtk-ui/sync-ui.c:481
+msgid "No service selected"
+msgstr "Nessun servizio selezionato"
-#: ../src/gtk-ui/sync-ui.c:799
-msgid "Last synced just seconds ago"
+#. TRANSLATORS: This is the title on main view. Placeholder is
+#. * the service name. Example: "Google - synced just now"
+#: ../src/gtk-ui/sync-ui.c:489
+#, fuzzy, c-format
+msgid "%s - synced just now"
msgstr "Ultima sincronizzazione pochi secondi fa"
-#: ../src/gtk-ui/sync-ui.c:802
-msgid "Last synced a minute ago"
+#: ../src/gtk-ui/sync-ui.c:493
+#, fuzzy, c-format
+msgid "%s - synced a minute ago"
msgstr "Ultima sincronizzazione un minuto fa"
-#: ../src/gtk-ui/sync-ui.c:805
-#, c-format
-msgid "Last synced %ld minutes ago"
+#: ../src/gtk-ui/sync-ui.c:497
+#, fuzzy, c-format
+msgid "%s - synced %ld minutes ago"
msgstr "Ultima sincronizzazione %ld minuti fa"
-#: ../src/gtk-ui/sync-ui.c:808
-msgid "Last synced an hour ago"
+#: ../src/gtk-ui/sync-ui.c:502
+#, fuzzy, c-format
+msgid "%s - synced an hour ago"
msgstr "Ultima sincronizzazione un'ora fa"
-#: ../src/gtk-ui/sync-ui.c:811
-#, c-format
-msgid "Last synced %ld hours ago"
+#: ../src/gtk-ui/sync-ui.c:506
+#, fuzzy, c-format
+msgid "%s - synced %ld hours ago"
msgstr "Ultima sincronizzazione %ld ore fa"
-#: ../src/gtk-ui/sync-ui.c:814
-msgid "Last synced a day ago"
+#: ../src/gtk-ui/sync-ui.c:511
+#, fuzzy, c-format
+msgid "%s - synced a day ago"
msgstr "Ultima sincronizzazione un giorno fa"
-#: ../src/gtk-ui/sync-ui.c:817
-#, c-format
-msgid "Last synced %ld days ago"
+#: ../src/gtk-ui/sync-ui.c:515
+#, fuzzy, c-format
+msgid "%s - synced %ld days ago"
msgstr "Ultima sincronizzazione %ld giorni fa"
+# (ndt) titolo finestra
+#. TRANSLATORS: Action buttons in error/info bars in main view.
+#: ../src/gtk-ui/sync-ui.c:563
+#: ../src/gtk-ui/ui.glade.h:35
+#, fuzzy
+msgid "Slow sync"
+msgstr "Sincronizzazione"
+
+#: ../src/gtk-ui/sync-ui.c:564
+msgid "Other options..."
+msgstr "Altre opzioni..."
+
+#: ../src/gtk-ui/sync-ui.c:567
+msgid "Select sync service"
+msgstr "Seleziona servizio di sincronizzazione"
+
+# (ndt) pulsante, sto sul corto
+#: ../src/gtk-ui/sync-ui.c:570
+msgid "Edit service settings"
+msgstr "Modifica impostazioni"
+
+#: ../src/gtk-ui/sync-ui.c:618
+#, fuzzy
+msgid "You haven't selected a sync service yet. Sync services let you synchronize your data between your netbook and a web service"
+msgstr ""
+"Non è ancora stato selezionato un servizio di sincronizzazione. Questi servizi\n"
+"consentono di sincronizzare i dati tra il proprio netbook e un servizio web."
+
# (ndt) pulsante
-#: ../src/gtk-ui/sync-ui.c:902
+#: ../src/gtk-ui/sync-ui.c:662
msgid "Sync again"
msgstr "Sincronizza ancora"
# (ndt) pulsante
-#: ../src/gtk-ui/sync-ui.c:904
-#: ../src/gtk-ui/ui.glade.h:29
+#: ../src/gtk-ui/sync-ui.c:664
msgid "Sync now"
msgstr "Sincronizza ora"
-#: ../src/gtk-ui/sync-ui.c:913
+#: ../src/gtk-ui/sync-ui.c:674
msgid "Syncing"
msgstr "Sincronizzazione"
# (ndt) pulsante
-#: ../src/gtk-ui/sync-ui.c:919
+#. TRANSLATORS: This is for the button in main view, right side.
+#. Keep line length below ~20 characters, use two lines if needed
+#: ../src/gtk-ui/sync-ui.c:683
msgid "Cancel sync"
msgstr "Annulla sincronizzazione"
-#. TRANSLATORS: placeholder is a source name, shown with checkboxes in main window
-#: ../src/gtk-ui/sync-ui.c:1266
+# (ndt) pulsante, dovrebbe tornare alla finestra principale
+#. TRANSLATORS: button in the Moblin window title bar when main view is
+#. * not visible
+#: ../src/gtk-ui/sync-ui.c:763
+msgid "Back to sync"
+msgstr "Torna indietro"
+
+#. This is the expander label in emergency view. It summarizes the
+#. * currently selected data sources. First placeholder is service/device
+#. * name, second a comma separeted list of sources.
+#. * E.g. "Affected data: Google Contacts, Appointments"
+#: ../src/gtk-ui/sync-ui.c:1134
+#, c-format
+msgid "Affected data: %s %s"
+msgstr "Dati interessati: %s %s"
+
+#: ../src/gtk-ui/sync-ui.c:1139
+#, c-format
+msgid "Affected data: none"
+msgstr "Dati interessati: nessuno"
+
+#. TRANSLATORS: confirmation for restoring a backup. placeholder is the
+#. * backup time string defined below
+#: ../src/gtk-ui/sync-ui.c:1214
#, c-format
-msgid "%s (not supported by this service)"
-msgstr "%s (non supportato da questo servizio)"
+msgid "Do you want to restore the backup from %s? All changes you have made since then will be lost."
+msgstr "Vuoi ripristinare il backup da% s? Tutte le modifiche apportate da allora saranno perse."
-#: ../src/gtk-ui/sync-ui.c:1299
+#: ../src/gtk-ui/sync-ui.c:1217
+msgid "Yes, restore"
+msgstr "Sì, ripristina"
+
+#: ../src/gtk-ui/sync-ui.c:1249
+#, c-format
+msgid "%x %X"
+msgstr "%x %X"
+
+#. TRANSLATORS: label for a backup in emergency view. Placeholder is
+#. * service or device name
+#: ../src/gtk-ui/sync-ui.c:1268
+#, c-format
+msgid "Backed up before syncing with %s"
+msgstr "Back up effettuato prima della sincronizzazione con %s"
+
+#: ../src/gtk-ui/sync-ui.c:1285
+msgid "Restore"
+msgstr "Ripristina"
+
+#. TRANSLATORS: this is an explanation in Emergency view.
+#. * Placeholder is a service/device name
+#: ../src/gtk-ui/sync-ui.c:1392
+#, c-format
+msgid "A normal sync with %s is not possible at this time. You can do a slow two-way sync, start from scratch or restore from backup."
+msgstr "Una sincronizzazione normale con % s non è possibile in questo momento. Si può fare una sincronizzazione lenta a due vie, iniziare da zero o ripristinare dal backup."
+
+#: ../src/gtk-ui/sync-ui.c:1400
#, c-format
+msgid "If something has gone horribly wrong, you can try a slow sync, start from scratch or restore from backup."
+msgstr "Se qualcosa è andato terribilmente storto, puoi provare una sincronizzazione lenta, iniziare da zero o ripristinare dal backup"
+
+#. TRANSLATORS: These are a buttons in Emergency view. Placeholder is a
+#. * service/device name. Please don't use too long lines, but feel free to
+#. * use several lines.
+#: ../src/gtk-ui/sync-ui.c:1409
+#, fuzzy, c-format
+msgid ""
+"Delete all your local\n"
+"data and replace with\n"
+"data from %s"
+msgstr "Eliminare i dati locali e sostituirli con quelli remoti"
+
+#: ../src/gtk-ui/sync-ui.c:1415
+#, fuzzy, c-format
+msgid ""
+"Delete all data on\n"
+"%s and replace\n"
+"with your local data"
+msgstr "Eliminare i dati remoti e sostituirli con quelli locali"
+
+#: ../src/gtk-ui/sync-ui.c:1854
+msgid "Failed to get list of supported services from SyncEvolution"
+msgstr "Recupero elenco dei servizi supportati da SyncEvolution non riuscito"
+
+#: ../src/gtk-ui/sync-ui.c:1958
+#: ../src/gtk-ui/sync-ui.c:2854
+#, fuzzy
+msgid "Sync failed"
+msgstr "Sincronizzazione non riuscita"
+
+#: ../src/gtk-ui/sync-ui.c:1962
+msgid "Sync complete"
+msgstr "Sincronizzazione completata"
+
+#: ../src/gtk-ui/sync-ui.c:2053
+#, c-format
+msgid "Preparing '%s'"
+msgstr "Preparazione di «%s»"
+
+#: ../src/gtk-ui/sync-ui.c:2056
+#, c-format
+msgid "Receiving '%s'"
+msgstr "Ricezione di «%s»"
+
+#: ../src/gtk-ui/sync-ui.c:2059
+#, c-format
+msgid "Sending '%s'"
+msgstr "Invio di «%s»"
+
+#: ../src/gtk-ui/sync-ui.c:2180
+#, fuzzy, c-format
msgid "There was one remote rejection."
-msgid_plural "There were %d remote rejections."
+msgid_plural "There were %ld remote rejections."
msgstr[0] "Si è verificato un rifiuto remoto."
msgstr[1] "Si sono verificati %d rifiuti remoti."
-#: ../src/gtk-ui/sync-ui.c:1304
-#, c-format
+#: ../src/gtk-ui/sync-ui.c:2185
+#, fuzzy, c-format
msgid "There was one local rejection."
-msgid_plural "There were %d local rejections."
+msgid_plural "There were %ld local rejections."
msgstr[0] "Si è verificato un rifiuto locale."
msgstr[1] "Si sono verificati %d rifiuti locali."
-#: ../src/gtk-ui/sync-ui.c:1309
-#, c-format
-msgid "There were %d local rejections and %d remote rejections."
+#: ../src/gtk-ui/sync-ui.c:2190
+#, fuzzy, c-format
+msgid "There were %ld local rejections and %ld remote rejections."
msgstr "Si sono verificati %d rifiuti locali e %d remoti."
-#: ../src/gtk-ui/sync-ui.c:1314
+#: ../src/gtk-ui/sync-ui.c:2195
#, c-format
msgid "Last time: No changes."
msgstr "Ultima volta: nessuna modifica."
-#: ../src/gtk-ui/sync-ui.c:1316
-#, c-format
+#: ../src/gtk-ui/sync-ui.c:2197
+#, fuzzy, c-format
msgid "Last time: Sent one change."
-msgid_plural "Last time: Sent %d changes."
+msgid_plural "Last time: Sent %ld changes."
msgstr[0] "Ultima volta: inviata una modifica."
msgstr[1] "Ultima volta: inviate %d modifiche."
#. This is about changes made to the local data. Not all of these
#. changes were requested by the remote server, so "applied"
#. is a better word than "received" (bug #5185).
-#: ../src/gtk-ui/sync-ui.c:1324
-#, c-format
+#: ../src/gtk-ui/sync-ui.c:2205
+#, fuzzy, c-format
msgid "Last time: Applied one change."
-msgid_plural "Last time: Applied %d changes."
+msgid_plural "Last time: Applied %ld changes."
msgstr[0] "Ultima volta: applicata una modifica."
msgstr[1] "Ultima volta: applicate %d modifiche."
-#: ../src/gtk-ui/sync-ui.c:1329
-#, c-format
-msgid "Last time: Applied %d changes and sent %d changes."
+#: ../src/gtk-ui/sync-ui.c:2210
+#, fuzzy, c-format
+msgid "Last time: Applied %ld changes and sent %ld changes."
msgstr "Ultima volta: applicate %d modifiche e inviate %d."
-#: ../src/gtk-ui/sync-ui.c:1421
-msgid "Failed to get server configuration from SyncEvolution"
-msgstr "Recupero della configurazione del server da SyncEvolution non riuscito"
-
-#: ../src/gtk-ui/sync-ui.c:1473
-msgid "ScheduleWorld enables you to keep your contacts, events, tasks, and notes in sync."
-msgstr "ScheduleWorld consente di tenere sincronizzati contatti, eventi, attività e note."
-
-#: ../src/gtk-ui/sync-ui.c:1476
-msgid "Google Sync can backup and synchronize your Address Book with your Gmail contacts."
-msgstr "Google Sync è in grado di eseguire delle copie di sicurezza e di sincronizzare la propria rubrica con i contatti di Gmail."
-
-#. TRANSLATORS: Please include the word "demo" (or the equivalent in
-#. your language): Funambol is going to be a 90 day demo service
-#. in the future
-#: ../src/gtk-ui/sync-ui.c:1482
-msgid "Backup your contacts and calendar. Sync with a singleclick, anytime, anywhere (DEMO)."
-msgstr "Eseguire una copia di sicurezza dei propri contatti e del proprio calendario. Sincronizzare con un solo clic, sempre, ovunque. (dimostrativo)"
-
-#: ../src/gtk-ui/sync-ui.c:1510
-msgid "New service"
-msgstr "Nuovo servizio"
+#: ../src/gtk-ui/sync-ui.c:2711
+msgid "Waiting for current operation to finish..."
+msgstr "In attesa che termini l'operazione..."
-#: ../src/gtk-ui/sync-ui.c:1557
-msgid "Server URL"
-msgstr "URL del server"
+#: ../src/gtk-ui/sync-ui.c:2784
+msgid "A normal sync is not possible at this time. The server suggests a slow sync, but this might not always be what you want if both ends already have data."
+msgstr "Una sincronizzazione normale non è possibile in questo momento. Il server suggerisce una sincronizzazione lenta, ma questo potrebbe non essere sempre quello che vuoi, se entrambe le estremità hanno dati."
-#. TRANSLATORS: placeholder is a source name in settings window
-#: ../src/gtk-ui/sync-ui.c:1579
-#, c-format
-msgid "%s URI"
-msgstr "URI di %s"
-
-# (ndt) è un collegamento
-#: ../src/gtk-ui/sync-ui.c:1716
-#: ../src/gtk-ui/ui.glade.h:17
-msgid "Launch website"
-msgstr "Visita il sito web"
-
-# (ndt) pulsante
-#: ../src/gtk-ui/sync-ui.c:1720
-msgid "Setup and use"
-msgstr "Configura e usa"
+#: ../src/gtk-ui/sync-ui.c:2791
+msgid "Failed to login. Could there be a problem with your username or password?"
+msgstr "Impossibile effettuare il login. Ci potrebbe essere un problema con il tuo nome utente o la password?"
-#: ../src/gtk-ui/sync-ui.c:1766
-msgid "Failed to get list of manually setup services from SyncEvolution"
-msgstr "Recupero elenco dei servizi configurati manualmente da SyncEvolution non riuscito"
-
-#: ../src/gtk-ui/sync-ui.c:1807
-msgid "Failed to get list of supported services from SyncEvolution"
-msgstr "Recupero elenco dei servizi supportati da SyncEvolution non riuscito"
-
-#. TODO: this is a hack... SyncEnd should be a signal of it's own,
-#. not just hacked on top of the syncevolution error codes
-#: ../src/gtk-ui/sync-ui.c:1968
-msgid "Service configuration not found"
-msgstr "Configurazione del servizio non trovata"
-
-#: ../src/gtk-ui/sync-ui.c:1974
-msgid "Not authorized"
-msgstr "Non autorizzato"
-
-#: ../src/gtk-ui/sync-ui.c:1976
+#: ../src/gtk-ui/sync-ui.c:2794
msgid "Forbidden"
msgstr "Proibito"
-#: ../src/gtk-ui/sync-ui.c:1978
-msgid "Not found"
-msgstr "Non trovato"
+#: ../src/gtk-ui/sync-ui.c:2799
+msgid "The source could not be found. Could there be a problem with the server settings?"
+msgstr "Impossibile trovare la sorgente. Ci potrebbe essere un problema con le impostazioni del server?"
-#: ../src/gtk-ui/sync-ui.c:1980
+#: ../src/gtk-ui/sync-ui.c:2802
msgid "Fatal database error"
msgstr "Errore grave nel database"
-#: ../src/gtk-ui/sync-ui.c:1982
+#. This can happen when EDS is borked, restart it may help...
+#: ../src/gtk-ui/sync-ui.c:2805
+msgid "There is a problem with the local database. Syncing again or rebooting may help."
+msgstr "C'è un problema con il database locale. Sincronizzare di nuovo o riavviare."
+
+#: ../src/gtk-ui/sync-ui.c:2808
msgid "Database error"
msgstr "Errore nel database"
-#: ../src/gtk-ui/sync-ui.c:1984
+#: ../src/gtk-ui/sync-ui.c:2810
msgid "No space left"
msgstr "Spazio esaurito"
-#. TODO identify problem item somehow ?
-#: ../src/gtk-ui/sync-ui.c:1987
+#: ../src/gtk-ui/sync-ui.c:2812
msgid "Failed to process SyncML"
msgstr "Elaborazione SyncML non riuscita"
-#: ../src/gtk-ui/sync-ui.c:1989
+#: ../src/gtk-ui/sync-ui.c:2814
msgid "Server authorization failed"
msgstr "Autorizzazione server non riuscita"
-#: ../src/gtk-ui/sync-ui.c:1991
+#: ../src/gtk-ui/sync-ui.c:2816
msgid "Failed to parse configuration file"
msgstr "Analisi del file di configurazione non riuscita"
-#: ../src/gtk-ui/sync-ui.c:1993
+#: ../src/gtk-ui/sync-ui.c:2818
msgid "Failed to read configuration file"
msgstr "Lettura del file di configurazione non riuscita"
-#: ../src/gtk-ui/sync-ui.c:1995
+#: ../src/gtk-ui/sync-ui.c:2820
msgid "No configuration found"
msgstr "Non è stata trovata alcuna configurazione"
-#: ../src/gtk-ui/sync-ui.c:1997
+#: ../src/gtk-ui/sync-ui.c:2822
msgid "No configuration file found"
msgstr "Non è stato trovato alcun file di configurazione"
-#: ../src/gtk-ui/sync-ui.c:1999
+#: ../src/gtk-ui/sync-ui.c:2824
msgid "Server sent bad content"
msgstr "Il server ha inviato dei contenuti errati"
-#: ../src/gtk-ui/sync-ui.c:2001
-msgid "Transport failure (no connection?)"
-msgstr "Errore nel trasporto dei dati (connessione assente?)"
-
-#: ../src/gtk-ui/sync-ui.c:2003
-msgid "Connection timed out"
-msgstr "La connessione è terminata"
-
-#: ../src/gtk-ui/sync-ui.c:2005
+#: ../src/gtk-ui/sync-ui.c:2826
msgid "Connection certificate has expired"
msgstr "Il certificato della connessione è scaduto"
-#: ../src/gtk-ui/sync-ui.c:2007
+#: ../src/gtk-ui/sync-ui.c:2828
msgid "Connection certificate is invalid"
msgstr "Il certificato della connessione non è valido"
-#: ../src/gtk-ui/sync-ui.c:2010
-msgid "Connection failed"
-msgstr "La connessione non è stata stabilita"
+#: ../src/gtk-ui/sync-ui.c:2836
+msgid "We were unable to connect to the server. The problem could be temporary or there could be something wrong with the server settings."
+msgstr "Non siamo stati in grado di connetterci al server. Il problema potrebbe essere temporaneo o ci potrebbe essere qualcosa di sbagliato con le impostazioni del server."
-#: ../src/gtk-ui/sync-ui.c:2012
+#: ../src/gtk-ui/sync-ui.c:2840
msgid "URL is bad"
msgstr "L'URL non è corretto"
-#: ../src/gtk-ui/sync-ui.c:2014
+#: ../src/gtk-ui/sync-ui.c:2842
msgid "Server not found"
msgstr "Il server non è stato trovato"
-#: ../src/gtk-ui/sync-ui.c:2016
+#: ../src/gtk-ui/sync-ui.c:2844
#, c-format
msgid "Error %d"
msgstr "Errore %d"
-#: ../src/gtk-ui/sync-ui.c:2026
-msgid "Sync D-Bus service exited unexpectedly"
-msgstr "Il servizio di sincronizzazione di D-Bus è terminato inaspettatamente"
-
-#: ../src/gtk-ui/sync-ui.c:2029
-#: ../src/gtk-ui/sync-ui.c:2080
-msgid "Sync Failed"
-msgstr "Sincronizzazione non riuscita"
-
-#: ../src/gtk-ui/sync-ui.c:2072
-msgid "Sync complete"
-msgstr "Sincronizzazione completata"
-
-#: ../src/gtk-ui/sync-ui.c:2077
-msgid "Sync canceled"
-msgstr "Sincronizzazione annullata"
-
-#. NOTE extra1 can be error here
-#: ../src/gtk-ui/sync-ui.c:2095
-msgid "Ending sync"
-msgstr "Termine sincronizzazione"
-
-#. TRANSLATORS: placeholder is a source name (e.g. 'Calendar') in a progress text
-#: ../src/gtk-ui/sync-ui.c:2119
-#, c-format
-msgid "Preparing '%s'"
-msgstr "Preparazione di «%s»"
-
-#. TRANSLATORS: placeholder is a source name in a progress text
-#: ../src/gtk-ui/sync-ui.c:2131
-#, c-format
-msgid "Sending '%s'"
-msgstr "Invio di «%s»"
-
-#. TRANSLATORS: placeholder is a source name in a progress text
-#: ../src/gtk-ui/sync-ui.c:2143
-#, c-format
-msgid "Receiving '%s'"
-msgstr "Ricezione di «%s»"
-
-#: ../src/gtk-ui/ui.glade.h:1
-msgid "<b>Data</b>"
-msgstr "<b>Dati</b>"
-
+#. title for the buttons on the right side of main view
#: ../src/gtk-ui/ui.glade.h:2
-msgid "<b>No sync service in use</b>"
-msgstr "<b>Nessun servizio di sincronizzazione in uso</b>"
-
-#: ../src/gtk-ui/ui.glade.h:3
-msgid "<b>Sync failure</b>"
-msgstr "<b>Sincronizzazione non riuscita</b>"
+#, fuzzy
+msgid "<b>Actions</b>"
+msgstr "<b>Dati</b>"
+#. text between the two "start from scratch" buttons in emergency view
#: ../src/gtk-ui/ui.glade.h:4
-msgid "<b>Type of Sync</b>"
-msgstr "<b>Tipo di sincronizzazione</b>"
+#, fuzzy
+msgid "<b>or</b>"
+msgstr "<b>Dati</b>"
#: ../src/gtk-ui/ui.glade.h:5
-msgid "<big>Manual setup</big>"
-msgstr "<big>Configurazione manuale</big>"
+#, fuzzy
+msgid "<big>Direct sync</big>"
+msgstr "<big>Servizi supportati</big>"
#: ../src/gtk-ui/ui.glade.h:6
-msgid "<big>Supported services</big>"
+#, fuzzy
+msgid "<big>Network sync</big>"
+msgstr "<b>Tipo di sincronizzazione</b>"
+
+#. a title in emergency view
+#: ../src/gtk-ui/ui.glade.h:8
+msgid "<big>Restore from backup</big>"
+msgstr "<big>Rirpistina dal backup</big>"
+
+#. a title in emergency view
+#: ../src/gtk-ui/ui.glade.h:10
+#, fuzzy
+msgid "<big>Slow sync</big>"
+msgstr "<big>Servizi supportati</big>"
+
+#. a title in emergency view
+#: ../src/gtk-ui/ui.glade.h:12
+#, fuzzy
+msgid "<big>Start from scratch</big>"
msgstr "<big>Servizi supportati</big>"
+#: ../src/gtk-ui/ui.glade.h:13
+msgid ""
+"A slow sync compares items from both sides and tries to merge them. \n"
+"This may fail in some cases, leading to duplicates or lost information."
+msgstr "Questo potrebbe non riuscire in alcuni casi, portando a duplicati o a informazioni perse."
+
# (ndt) pulsante
-#: ../src/gtk-ui/ui.glade.h:7
+#: ../src/gtk-ui/ui.glade.h:15
+msgid "Add new device"
+msgstr "Aggiungi un nuovo dispositivo"
+
+# (ndt) pulsante
+#: ../src/gtk-ui/ui.glade.h:16
msgid "Add new service"
msgstr "Aggiungi servizio"
-# (ndt) pulsante, dovrebbe tornare alla finestra principale
-#: ../src/gtk-ui/ui.glade.h:8
-msgid "Back to sync"
-msgstr "Torna indietro"
+#. explanation of "Restore backup" function
+#: ../src/gtk-ui/ui.glade.h:18
+msgid "Backups are made before every time we Sync. Choose a backup to restore. Any changes you have made since then will be lost."
+msgstr ""
+
+#: ../src/gtk-ui/ui.glade.h:19
+msgid "Calendar"
+msgstr "Calendario"
# (ndt) pulsante
-#: ../src/gtk-ui/ui.glade.h:9
+#. Button in main view, right side. Keep to below 20 chars per line, feel free to use two lines
+#: ../src/gtk-ui/ui.glade.h:21
+#, fuzzy
msgid ""
-"Change sync\n"
-"service"
+"Change or edit\n"
+"sync service"
msgstr ""
"Modifica servizio\n"
"di sincronizzazione"
-#: ../src/gtk-ui/ui.glade.h:11
-msgid "Delete all local data and replace it with remote data"
-msgstr "Eliminare i dati locali e sostituirli con quelli remoti"
-
-#: ../src/gtk-ui/ui.glade.h:12
-msgid "Delete all remote data and replace it with local data"
+#: ../src/gtk-ui/ui.glade.h:23
+#, fuzzy
+msgid ""
+"Delete all data on Zyb \n"
+"and replace with your\n"
+"local information"
msgstr "Eliminare i dati remoti e sostituirli con quelli locali"
-# (ndt) pulsante
-#: ../src/gtk-ui/ui.glade.h:13
-msgid "Delete this service"
-msgstr "Elimina servizio"
+#: ../src/gtk-ui/ui.glade.h:26
+#, fuzzy
+msgid ""
+"Delete all your local\n"
+"information and replace\n"
+"with data from Zyb"
+msgstr "Eliminare i dati locali e sostituirli con quelli remoti"
-# (ndt) pulsante, sto sul corto
-#: ../src/gtk-ui/ui.glade.h:14
-msgid "Edit service settings"
-msgstr "Modifica impostazioni"
+#. button in main view, right side. Keep length to 20 characters or so, use two lines if needed
+#: ../src/gtk-ui/ui.glade.h:30
+msgid ""
+"Fix a sync\n"
+"emergency"
+msgstr ""
# (ndt) segnalare SyncML?
-#: ../src/gtk-ui/ui.glade.h:15
+#: ../src/gtk-ui/ui.glade.h:32
msgid ""
"If you don't see your service above but know that your sync provider uses SyncML\n"
"you can setup a service manually."
"Se non vengono visualizzati i propri servizi, ma si è certi che il proprio provider\n"
"usa SyncML, è possibile impostare un servizio manualmente."
-#: ../src/gtk-ui/ui.glade.h:18
-msgid "Merge local and remote data (recommended)"
-msgstr "Unire i dati locali e remoti (raccomandato)"
-
-#: ../src/gtk-ui/ui.glade.h:19
-msgid "Password"
-msgstr "Password"
-
-# (ndt) pulsante
-#: ../src/gtk-ui/ui.glade.h:20
-msgid "Reset original server settings"
-msgstr "Ripristina valori originali"
-
-# (ndt) pulsante
-#: ../src/gtk-ui/ui.glade.h:21
-msgid "Save and use this service"
-msgstr "Salva e usa il servizio"
-
-#: ../src/gtk-ui/ui.glade.h:22
-msgid "Select sync service"
-msgstr "Seleziona servizio di sincronizzazione"
-
-#: ../src/gtk-ui/ui.glade.h:23
-msgid "Server settings"
-msgstr "Impostazioni server"
-
-#: ../src/gtk-ui/ui.glade.h:24
-msgid "Service name"
-msgstr "Nome servizio"
+#: ../src/gtk-ui/ui.glade.h:34
+msgid "Settings"
+msgstr "Impostazioni"
-#: ../src/gtk-ui/ui.glade.h:25
-msgid ""
-"Sorry, you need an internet\n"
-"connection to sync."
+#: ../src/gtk-ui/ui.glade.h:37
+msgid "Sync Emergency"
msgstr ""
-"È necessaria una connessione a\n"
-"Internet per la sincronizzazione."
-
-# (ndt) pulsante
-#: ../src/gtk-ui/ui.glade.h:27
-msgid "Stop using this service"
-msgstr "Non usare più"
-
-#: ../src/gtk-ui/ui.glade.h:30
-msgid "Synchronization is not available (D-Bus service does not answer), sorry."
-msgstr "La sincronizzazione non è disponibile (il servizio D-Bus non è attivo)."
-#: ../src/gtk-ui/ui.glade.h:31
+#: ../src/gtk-ui/ui.glade.h:39
msgid ""
"To sync you'll need a network connection and an account with a sync service.\n"
"We support the following services: "
"Per effettuare la sincronizzazione sono necessari una connessione e un account con un servizio di sincronizzazione.\n"
"I servizi supportati sono: "
-#: ../src/gtk-ui/ui.glade.h:33
-msgid "Username"
-msgstr "Nome utente"
+#: ../src/gtk-ui/ui.glade.h:41
+msgid "Use Bluetooth to Sync your data from one device to another."
+msgstr ""
-#: ../src/gtk-ui/ui.glade.h:34
-msgid ""
-"You haven't selected a sync service yet. Sync services let you \n"
-"synchronize your data between your netbook and a web service."
+#: ../src/gtk-ui/ui.glade.h:42
+msgid "You will need to add Bluetooth devices before they can be synced."
msgstr ""
-"Non è ancora stato selezionato un servizio di sincronizzazione. Questi servizi\n"
-"consentono di sincronizzare i dati tra il proprio netbook e un servizio web."
#: ../src/gtk-ui/sync.desktop.in.h:2
#: ../src/gtk-ui/sync-gtk.desktop.in.h:2
msgid "Sync (GTK)"
msgstr "Sync (GTK)"
-#~ msgid "Bring your data with you"
-#~ msgstr "Portare i dati con sé"
+#: ../src/gtk-ui/sync-config-widget.c:71
+msgid "ScheduleWorld enables you to keep your contacts, events, tasks, and notes in sync."
+msgstr "ScheduleWorld consente di tenere sincronizzati contatti, eventi, attività e note."
+
+#: ../src/gtk-ui/sync-config-widget.c:74
+msgid "Google Sync can backup and synchronize your contacts with your Gmail contacts."
+msgstr "Google Sync è in grado di eseguire backup di sicurezza e di sincronizzare la propria rubrica con i contatti di Gmail."
+
+#. TRANSLATORS: Please include the word "demo" (or the equivalent in
+#. your language): Funambol is going to be a 90 day demo service
+#. in the future
+#: ../src/gtk-ui/sync-config-widget.c:80
+msgid "Backup your contacts and calendar. Sync with a single click, anytime, anywhere (DEMO)."
+msgstr "Eseguire una copia di sicurezza dei propri contatti e del proprio calendario. Sincronizzare con un solo clic, sempre e ovunque (dimostrativo)."
+
+#: ../src/gtk-ui/sync-config-widget.c:83
+msgid "Mobical Backup and Restore service allows you to securely backup your personal mobile data for free."
+msgstr ""
+
+#: ../src/gtk-ui/sync-config-widget.c:86
+msgid "ZYB is a simple way for people to store and share mobile information online."
+msgstr ""
+
+#: ../src/gtk-ui/sync-config-widget.c:89
+msgid "Memotoo lets you access your personal data from any computer connected to the Internet."
+msgstr ""
+
+#: ../src/gtk-ui/sync-config-widget.c:255
+#, c-format
+msgid "Do you want to replace %s with %s? This will not remove any synced information on either end but you will no longer be able to sync with %s."
+msgstr ""
+
+#. TRANSLATORS: decline/accept buttons in warning dialog.
+#. Placeholder is service name
+#: ../src/gtk-ui/sync-config-widget.c:267
+#, c-format
+msgid "Yes, use %s"
+msgstr "Sì, utilizza %s"
+
+#: ../src/gtk-ui/sync-config-widget.c:268
+#, c-format
+msgid "No, use %s"
+msgstr "No, utilizza %s"
+
+#: ../src/gtk-ui/sync-config-widget.c:341
+msgid "Service must have a name and server URL"
+msgstr "Il servizio deve avere un nome e un indirizzo del server"
+
+#: ../src/gtk-ui/sync-config-widget.c:381
+#, c-format
+msgid "Do you want to reset the settings for %s? This will not remove any synced information on either end."
+msgstr ""
+
+#. TRANSLATORS: buttons in reset-service warning dialog
+#: ../src/gtk-ui/sync-config-widget.c:385
+msgid "Yes, reset"
+msgstr "Sì, ripristina"
+
+#: ../src/gtk-ui/sync-config-widget.c:386
+#: ../src/gtk-ui/sync-config-widget.c:397
+msgid "No, keep settings"
+msgstr "No, mantieni le impostazioni"
+
+#: ../src/gtk-ui/sync-config-widget.c:391
+#, c-format
+msgid "Do you want to delete the settings for %s? This will not remove any synced information on either end but it will remove this service configuration."
+msgstr ""
+
+# (ndt) pulsante
+#. TRANSLATORS: buttons in delete-service warning dialog
+#: ../src/gtk-ui/sync-config-widget.c:396
+msgid "Yes, delete"
+msgstr "Sì, elimina"
+
+#: ../src/gtk-ui/sync-config-widget.c:425
+msgid "Reset service"
+msgstr "Servizio di ripristino"
+
+# (ndt) pulsante
+#: ../src/gtk-ui/sync-config-widget.c:428
+msgid "Delete service"
+msgstr "Elimina servizio"
+
+# (ndt) pulsante
+#: ../src/gtk-ui/sync-config-widget.c:438
+msgid "Save and use"
+msgstr "Salva e usa"
+
+# (ndt) pulsante
+#: ../src/gtk-ui/sync-config-widget.c:441
+msgid ""
+"Save and replace\n"
+"current service"
+msgstr ""
+"Salva e sostituisci\n"
+" il servizio"
+
+#. TRANSLATORS: label for an entry in service configuration form.
+#. * Placeholder is a source name.
+#. * Example: "Appointments URI"
+#: ../src/gtk-ui/sync-config-widget.c:672
+#, c-format
+msgid "%s URI"
+msgstr "URI di %s"
+
+#. TRANSLATORS: toggles in service configuration form, placeholder is service
+#. * or device name
+#: ../src/gtk-ui/sync-config-widget.c:850
+#, c-format
+msgid "Send changes to %s"
+msgstr "Invia modifiche a %s"
+
+#: ../src/gtk-ui/sync-config-widget.c:854
+#, c-format
+msgid "Receive changes from %s"
+msgstr ""
+
+#: ../src/gtk-ui/sync-config-widget.c:869
+msgid "<b>Sync</b>"
+msgstr "<b>Sincronizzazione</b>"
+
+#. TRANSLATORS: label of a entry in service configuration
+#: ../src/gtk-ui/sync-config-widget.c:885
+msgid "Server address"
+msgstr "Indirizzo server"
+
+#: ../src/gtk-ui/sync-config-widget.c:1067
+#, c-format
+msgid "%s - Bluetooth device"
+msgstr ""
+
+#. TRANSLATORS: service title for services that are not based on a
+#. * template in service list, the placeholder is the name of the service
+#: ../src/gtk-ui/sync-config-widget.c:1073
+#, c-format
+msgid "%s - manually setup"
+msgstr ""
+
+# (ndt) è un collegamento
+#. TRANSLATORS: link button in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1748
+msgid "Launch website"
+msgstr "Visita il sito web"
+
+# (ndt) pulsante
+#. TRANSLATORS: button in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1757
+msgid "Setup now"
+msgstr "Configura adesso"
+
+#. TRANSLATORS: labels of entries in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1820
+msgid "Username"
+msgstr "Nome utente"
+
+#: ../src/gtk-ui/sync-config-widget.c:1835
+msgid "Password"
+msgstr "Password"
+
+#. TRANSLATORS: warning in service configuration form for people
+#. who have modified the configuration via other means.
+#: ../src/gtk-ui/sync-config-widget.c:1858
+msgid "Current service configuration is more complex than what can be shown here. Changes to sync mode or synced data types will overwrite that configuration."
+msgstr ""
+
+#. TRANSLATORS: this is the epander label for server settings
+#. in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1877
+msgid "Hide server settings"
+msgstr "Nascondi impostazioni server"
+
+#. TRANSLATORS: this is the epander label for server settings
+#. in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1897
+msgid "Show server settings"
+msgstr "Mostra impostazioni server"
+
+# (ndt) pulsante
+#. TRANSLATORS: button in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1910
+msgid "Stop using service"
+msgstr "Non usare il servizio"
+
+#: ../src/gnome-bluetooth/syncevolution.c:110
+msgid "Sync in the Sync application"
+msgstr ""
+
+#~ msgid "Addressbook"
+#~ msgstr "Rubrica"
+#~ msgid "Todo"
+#~ msgstr "Attività"
+#~ msgid "Memo"
+#~ msgstr "Memo"
+#~ msgid "Failed to save current service in GConf configuration system"
+#~ msgstr ""
+#~ "Salvataggio del servizio attuale nel sistema di configurazione GConf non "
+#~ "riuscito"
+#~ msgid "Failed to save service configuration to SyncEvolution"
+#~ msgstr ""
+#~ "Salvataggio della configurazione del servizio in SyncEvolution non "
+#~ "riuscito"
+#~ msgid "Failed to get service configuration from SyncEvolution"
+#~ msgstr ""
+#~ "Recupero della configurazione del servizio da SyncEvolution non riuscito"
+#~ msgid "Failed to remove service configuration from SyncEvolution"
+#~ msgstr ""
+#~ "Rimozione della configurazione del servizio da SyncEvolution non riuscita"
+#~ msgid "Failed to cancel: sync was no longer in progress"
+#~ msgstr "Annullamento non riuscito: la sincronizzazione non era più in corso"
+#~ msgid "Failed to cancel sync"
+#~ msgstr "Annullamento sincronizzazione non riuscito"
+#~ msgid "Canceling sync"
+#~ msgstr "Annullamento sincronizzazione"
+#~ msgid "No sources are enabled, not syncing"
+#~ msgstr "Nessuna sorgente è abilitata, niente da sincronizzare"
+#~ msgid "A sync is already in progress"
+#~ msgstr "È già in corso una sincronizzazione"
+#~ msgid "Failed to start sync"
+#~ msgstr "Avvio della sincronizzazione non riuscito"
+#~ msgid "%s (not supported by this service)"
+#~ msgstr "%s (non supportato da questo servizio)"
+#~ msgid "Failed to get server configuration from SyncEvolution"
+#~ msgstr ""
+#~ "Recupero della configurazione del server da SyncEvolution non riuscito"
+#~ msgid "Server URL"
+#~ msgstr "URL del server"
+#~ msgid "Failed to get list of manually setup services from SyncEvolution"
+#~ msgstr ""
+#~ "Recupero elenco dei servizi configurati manualmente da SyncEvolution non "
+#~ "riuscito"
+#~ msgid "Service configuration not found"
+#~ msgstr "Configurazione del servizio non trovata"
+#~ msgid "Not authorized"
+#~ msgstr "Non autorizzato"
+#~ msgid "Not found"
+#~ msgstr "Non trovato"
+#~ msgid "Transport failure (no connection?)"
+#~ msgstr "Errore nel trasporto dei dati (connessione assente?)"
+#~ msgid "Connection timed out"
+#~ msgstr "La connessione è terminata"
+#~ msgid "Connection failed"
+#~ msgstr "La connessione non è stata stabilita"
+#~ msgid "Sync D-Bus service exited unexpectedly"
+#~ msgstr ""
+#~ "Il servizio di sincronizzazione di D-Bus è terminato inaspettatamente"
+#~ msgid "Sync canceled"
+#~ msgstr "Sincronizzazione annullata"
+#~ msgid "Ending sync"
+#~ msgstr "Termine sincronizzazione"
+#~ msgid "<b>No sync service in use</b>"
+#~ msgstr "<b>Nessun servizio di sincronizzazione in uso</b>"
+#~ msgid "<big>Manual setup</big>"
+#~ msgstr "<big>Configurazione manuale</big>"
+#~ msgid "Merge local and remote data (recommended)"
+#~ msgstr "Unire i dati locali e remoti (raccomandato)"
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: http://moblin.org/projects/syncevolution\n"
-"POT-Creation-Date: 2009-12-21 18:45+0000\n"
+"POT-Creation-Date: 2010-02-12 00:01+0000\n"
"PO-Revision-Date: \n"
"Last-Translator: Cheng-Chia Tseng <pswo10680@gmail.com>\n"
"Language-Team: \n"
#. TRANSLATORS: this is the application name that may be used by e.g.
#. the windowmanager
-#: ../src/gtk-ui/main.c:31
-#: ../src/gtk-ui/ui.glade.h:20
+#: ../src/gtk-ui/main.c:40
+#: ../src/gtk-ui/ui.glade.h:36
#: ../src/gtk-ui/sync.desktop.in.h:1
+#: ../src/gnome-bluetooth/syncevolution.c:112
msgid "Sync"
msgstr "同步"
-#. TRANSLATORS: The name was changed from 'Addressbook' to
-#. 'Contacts' to match naming in rest of moblin. Please make sure the
-#. name you use matches the name in the panel and Contacts application.
-#: ../src/gtk-ui/sync-ui.c:192
+#: ../src/gtk-ui/sync-ui.c:234
msgid "Contacts"
msgstr "連絡人"
-#: ../src/gtk-ui/sync-ui.c:194
-msgid "Calendar"
-msgstr "行事曆"
+#: ../src/gtk-ui/sync-ui.c:236
+msgid "Appointments"
+msgstr "約會"
-#: ../src/gtk-ui/sync-ui.c:196
-msgid "Todo"
-msgstr "要做的事"
+#: ../src/gtk-ui/sync-ui.c:238
+#: ../src/gtk-ui/ui.glade.h:38
+msgid "Tasks"
+msgstr "工作"
-#: ../src/gtk-ui/sync-ui.c:198
-msgid "Memo"
-msgstr "備忘錄"
+#: ../src/gtk-ui/sync-ui.c:240
+msgid "Notes"
+msgstr "註記"
-#. TODO show in UI: failed to abort sync (while syncing)
-#: ../src/gtk-ui/sync-ui.c:273
-msgid "Failed to abort sync"
-msgstr "放棄同步時失敗"
+#. TRANSLATORS: This is a "combination source" for syncing with devices
+#. * that combine appointments and tasks. the name should match the ones
+#. * used for calendar and todo above
+#: ../src/gtk-ui/sync-ui.c:245
+msgid "Appointments & Tasks"
+msgstr "約會與工作"
-#. TODO show in UI: sync failed (failed to even start)
-#: ../src/gtk-ui/sync-ui.c:287
-msgid "Failed to start sync"
-msgstr "開始同步動作失敗"
-
-#: ../src/gtk-ui/sync-ui.c:293
+#: ../src/gtk-ui/sync-ui.c:317
msgid "Starting sync"
msgstr "正在開始同步"
-#: ../src/gtk-ui/sync-ui.c:309
-msgid "Trying to cancel sync"
-msgstr "正在嘗試取消同步"
+#. TRANSLATORS: slow sync confirmation dialog message. Placeholder
+#. * is service/device name
+#: ../src/gtk-ui/sync-ui.c:355
+#, c-format
+msgid "Do you want to slow sync with %s?"
+msgstr "你想要與 %s 進行慢速同步嗎?"
+
+#: ../src/gtk-ui/sync-ui.c:359
+msgid "Yes, do slow sync"
+msgstr "是,執行慢速同步"
-#: ../src/gtk-ui/sync-ui.c:316
+#: ../src/gtk-ui/sync-ui.c:359
+msgid "No, cancel sync"
+msgstr "不,取消同步"
+
+#. TRANSLATORS: confirmation dialog for refresh-from-server. Placeholder
+#. * is service/device name
+#: ../src/gtk-ui/sync-ui.c:392
#, c-format
msgid "Do you want to delete all local data and replace it with data from %s? This is not usually advised."
msgstr "你要刪除所有本機資料,並使用 %s 上的資料取代它嗎?我們通常不建議這麼做。"
-#: ../src/gtk-ui/sync-ui.c:321
+#: ../src/gtk-ui/sync-ui.c:397
+#: ../src/gtk-ui/sync-ui.c:428
+msgid "Yes, delete and replace"
+msgstr "是,刪除並取代"
+
+#: ../src/gtk-ui/sync-ui.c:397
+#: ../src/gtk-ui/sync-ui.c:428
+#: ../src/gtk-ui/sync-ui.c:1217
+msgid "No"
+msgstr "否"
+
+#. TRANSLATORS: confirmation dialog for refresh-from-client. Placeholder
+#. * is service/device name
+#: ../src/gtk-ui/sync-ui.c:423
#, c-format
msgid "Do you want to delete all data in %s and replace it with your local data? This is not usually advised."
-msgstr "你要刪除所有在 %s 上的資料,並且使用本地資料取代它嗎?我們通常不建議這麼做。"
+msgstr "你要刪除所有在 %s 上的資料,並且使用本機資料取代它嗎?我們通常不建議這麼做。"
-#: ../src/gtk-ui/sync-ui.c:338
-msgid "No, cancel sync"
-msgstr "不,取消同步"
+#: ../src/gtk-ui/sync-ui.c:455
+msgid "Trying to cancel sync"
+msgstr "正在嘗試取消同步"
-#: ../src/gtk-ui/sync-ui.c:340
-msgid "Yes, delete and replace"
-msgstr "æ\98¯ï¼\8cå\88ªé\99¤ä¸¦å\8f\96代"
+#: ../src/gtk-ui/sync-ui.c:481
+msgid "No service selected"
+msgstr "æ\9cªé\81¸å\8f\96æ\9c\8då\8b\99"
-#: ../src/gtk-ui/sync-ui.c:377
-msgid "Last synced just seconds ago"
-msgstr "最後一次同步是在幾秒鐘以前"
+#. TRANSLATORS: This is the title on main view. Placeholder is
+#. * the service name. Example: "Google - synced just now"
+#: ../src/gtk-ui/sync-ui.c:489
+#, c-format
+msgid "%s - synced just now"
+msgstr "%s - 剛才同步過"
-#: ../src/gtk-ui/sync-ui.c:380
-msgid "Last synced a minute ago"
-msgstr "最後一次同步是在一分鐘以前"
+#: ../src/gtk-ui/sync-ui.c:493
+#, c-format
+msgid "%s - synced a minute ago"
+msgstr "%s - 一分鐘前同步過"
-#: ../src/gtk-ui/sync-ui.c:383
+#: ../src/gtk-ui/sync-ui.c:497
#, c-format
-msgid "Last synced %ld minutes ago"
-msgstr "最後一次同步是在 %ld 分鐘以前"
+msgid "%s - synced %ld minutes ago"
+msgstr "%s - %ld 分鐘前同步過"
-#: ../src/gtk-ui/sync-ui.c:386
-msgid "Last synced an hour ago"
-msgstr "最後一次同步是在一小時以前"
+#: ../src/gtk-ui/sync-ui.c:502
+#, c-format
+msgid "%s - synced an hour ago"
+msgstr "%s - 一小時前同步過"
-#: ../src/gtk-ui/sync-ui.c:389
+#: ../src/gtk-ui/sync-ui.c:506
#, c-format
-msgid "Last synced %ld hours ago"
-msgstr "最後一次同步是在 %ld 小時以前"
+msgid "%s - synced %ld hours ago"
+msgstr "%s - %ld 小時前同步過"
-#: ../src/gtk-ui/sync-ui.c:392
-msgid "Last synced a day ago"
-msgstr "最後一次同步是在一天以前"
+#: ../src/gtk-ui/sync-ui.c:511
+#, c-format
+msgid "%s - synced a day ago"
+msgstr "%s - 一天前同步過"
-#: ../src/gtk-ui/sync-ui.c:395
+#: ../src/gtk-ui/sync-ui.c:515
#, c-format
-msgid "Last synced %ld days ago"
-msgstr "最後一次同步是在 %ld 天以前"
+msgid "%s - synced %ld days ago"
+msgstr "%s - %ld 天前同步過"
+
+#. TRANSLATORS: Action buttons in error/info bars in main view.
+#: ../src/gtk-ui/sync-ui.c:563
+#: ../src/gtk-ui/ui.glade.h:35
+msgid "Slow sync"
+msgstr "慢速同步"
+
+#: ../src/gtk-ui/sync-ui.c:564
+msgid "Other options..."
+msgstr "其他選項..."
+
+#: ../src/gtk-ui/sync-ui.c:567
+msgid "Select sync service"
+msgstr "選取同步服務"
-#: ../src/gtk-ui/sync-ui.c:480
+#: ../src/gtk-ui/sync-ui.c:570
+msgid "Edit service settings"
+msgstr "編輯服務設定"
+
+#: ../src/gtk-ui/sync-ui.c:618
+msgid "You haven't selected a sync service yet. Sync services let you synchronize your data between your netbook and a web service"
+msgstr "你尚未選取同步服務。同步服務讓你在你的網路筆電與網路服務間同步你的資料"
+
+#: ../src/gtk-ui/sync-ui.c:662
msgid "Sync again"
msgstr "再次同步"
-#: ../src/gtk-ui/sync-ui.c:482
-#: ../src/gtk-ui/ui.glade.h:21
+#: ../src/gtk-ui/sync-ui.c:664
msgid "Sync now"
msgstr "現在同步"
-#: ../src/gtk-ui/sync-ui.c:493
+#: ../src/gtk-ui/sync-ui.c:674
msgid "Syncing"
msgstr "正在同步中"
-#: ../src/gtk-ui/sync-ui.c:499
+#. TRANSLATORS: This is for the button in main view, right side.
+#. Keep line length below ~20 characters, use two lines if needed
+#: ../src/gtk-ui/sync-ui.c:683
msgid "Cancel sync"
msgstr "取消同步"
-#. TRANSLATORS: placeholder is a source name, shown with checkboxes in main window
-#: ../src/gtk-ui/sync-ui.c:849
+#. TRANSLATORS: button in the Moblin window title bar when main view is
+#. * not visible
+#: ../src/gtk-ui/sync-ui.c:763
+msgid "Back to sync"
+msgstr "返回同步"
+
+#. This is the expander label in emergency view. It summarizes the
+#. * currently selected data sources. First placeholder is service/device
+#. * name, second a comma separeted list of sources.
+#. * E.g. "Affected data: Google Contacts, Appointments"
+#: ../src/gtk-ui/sync-ui.c:1134
+#, c-format
+msgid "Affected data: %s %s"
+msgstr "受影響的資料:%s %s"
+
+#: ../src/gtk-ui/sync-ui.c:1139
+#, c-format
+msgid "Affected data: none"
+msgstr "受影響的資料:無"
+
+#. TRANSLATORS: confirmation for restoring a backup. placeholder is the
+#. * backup time string defined below
+#: ../src/gtk-ui/sync-ui.c:1214
+#, c-format
+msgid "Do you want to restore the backup from %s? All changes you have made since then will be lost."
+msgstr "你想要還原來自 %s 的備份嗎?所有你從那時起的變更都會喪失。"
+
+#: ../src/gtk-ui/sync-ui.c:1217
+msgid "Yes, restore"
+msgstr "是,還原"
+
+#: ../src/gtk-ui/sync-ui.c:1249
+#, c-format
+msgid "%x %X"
+msgstr "%x %X"
+
+#. TRANSLATORS: label for a backup in emergency view. Placeholder is
+#. * service or device name
+#: ../src/gtk-ui/sync-ui.c:1268
#, c-format
-msgid "%s (not supported by this service)"
-msgstr "%s (不被此服務支援)"
+msgid "Backed up before syncing with %s"
+msgstr "在與 %s 同步前已備份"
-#: ../src/gtk-ui/sync-ui.c:1046
-msgid "Failed to get list of configured services from SyncEvolution"
-msgstr "從 SyncEvolution 取得已設定的服務清單時失敗"
+#: ../src/gtk-ui/sync-ui.c:1285
+msgid "Restore"
+msgstr "還原"
-#: ../src/gtk-ui/sync-ui.c:1117
+#. TRANSLATORS: this is an explanation in Emergency view.
+#. * Placeholder is a service/device name
+#: ../src/gtk-ui/sync-ui.c:1392
+#, c-format
+msgid "A normal sync with %s is not possible at this time. You can do a slow two-way sync, start from scratch or restore from backup."
+msgstr "與 %s 的一般同步目前無法使用。你可以嘗試慢速雙方同步、從零開始或是從備份中還原。"
+
+#: ../src/gtk-ui/sync-ui.c:1400
+#, c-format
+msgid "If something has gone horribly wrong, you can try a slow sync, start from scratch or restore from backup."
+msgstr "如果有東西發生可怕錯誤,你可以嘗試慢速同步、從零開始或是從備份還原。"
+
+#. TRANSLATORS: These are a buttons in Emergency view. Placeholder is a
+#. * service/device name. Please don't use too long lines, but feel free to
+#. * use several lines.
+#: ../src/gtk-ui/sync-ui.c:1409
+#, c-format
+msgid ""
+"Delete all your local\n"
+"data and replace with\n"
+"data from %s"
+msgstr ""
+"刪除所有本機\n"
+"資料並使用來自\n"
+"%s 的資料取代"
+
+#: ../src/gtk-ui/sync-ui.c:1415
+#, c-format
+msgid ""
+"Delete all data on\n"
+"%s and replace\n"
+"with your local data"
+msgstr ""
+"刪除所有 %s 上的\n"
+"資料並使用你的本機\n"
+"資料取代"
+
+#: ../src/gtk-ui/sync-ui.c:1854
msgid "Failed to get list of supported services from SyncEvolution"
msgstr "從 SyncEvolution 取得支援的服務清單時失敗"
-#: ../src/gtk-ui/sync-ui.c:1221
+#: ../src/gtk-ui/sync-ui.c:1958
+#: ../src/gtk-ui/sync-ui.c:2854
+msgid "Sync failed"
+msgstr "同步失敗"
+
+#: ../src/gtk-ui/sync-ui.c:1962
msgid "Sync complete"
msgstr "同步完成"
-#: ../src/gtk-ui/sync-ui.c:1310
+#: ../src/gtk-ui/sync-ui.c:2053
#, c-format
msgid "Preparing '%s'"
msgstr "正在準備 '%s'"
-#: ../src/gtk-ui/sync-ui.c:1313
+#: ../src/gtk-ui/sync-ui.c:2056
#, c-format
msgid "Receiving '%s'"
msgstr "正在接收 '%s'"
-#: ../src/gtk-ui/sync-ui.c:1316
+#: ../src/gtk-ui/sync-ui.c:2059
#, c-format
msgid "Sending '%s'"
-msgstr "正在發送 '%s'"
+msgstr "正在傳送「%s」"
+
+#: ../src/gtk-ui/sync-ui.c:2180
+#, c-format
+msgid "There was one remote rejection."
+msgid_plural "There were %ld remote rejections."
+msgstr[0] "有過一次遠端拒絕。"
+msgstr[1] "有過 %ld 次遠端拒絕。"
+
+#: ../src/gtk-ui/sync-ui.c:2185
+#, c-format
+msgid "There was one local rejection."
+msgid_plural "There were %ld local rejections."
+msgstr[0] "有過一次本機拒絕。"
+msgstr[1] "有過 %ld 次本機拒絕。"
+
+#: ../src/gtk-ui/sync-ui.c:2190
+#, c-format
+msgid "There were %ld local rejections and %ld remote rejections."
+msgstr "有過 %ld 次本機拒絕和 %ld 次遠端拒絕。"
-#: ../src/gtk-ui/sync-ui.c:1705
+#: ../src/gtk-ui/sync-ui.c:2195
+#, c-format
+msgid "Last time: No changes."
+msgstr "上次:沒有變更。"
+
+#: ../src/gtk-ui/sync-ui.c:2197
+#, c-format
+msgid "Last time: Sent one change."
+msgid_plural "Last time: Sent %ld changes."
+msgstr[0] "上次:傳送了一個變更。"
+msgstr[1] "上次:傳送了 %ld 個變更。"
+
+#. This is about changes made to the local data. Not all of these
+#. changes were requested by the remote server, so "applied"
+#. is a better word than "received" (bug #5185).
+#: ../src/gtk-ui/sync-ui.c:2205
+#, c-format
+msgid "Last time: Applied one change."
+msgid_plural "Last time: Applied %ld changes."
+msgstr[0] "上次:套用了一個變更。"
+msgstr[1] "上次:套用了 %ld 個變更。"
+
+#: ../src/gtk-ui/sync-ui.c:2210
+#, c-format
+msgid "Last time: Applied %ld changes and sent %ld changes."
+msgstr "上次:套用了 %ld 個變更並傳送了 %ld 個變更。"
+
+#: ../src/gtk-ui/sync-ui.c:2711
msgid "Waiting for current operation to finish..."
msgstr "正在等候目前的操作完成..."
-#: ../src/gtk-ui/sync-ui.c:1750
-msgid "Not authorized"
-msgstr "未授權"
+#: ../src/gtk-ui/sync-ui.c:2784
+msgid "A normal sync is not possible at this time. The server suggests a slow sync, but this might not always be what you want if both ends already have data."
+msgstr "一般同步目前無法使用。這台伺服器建議使用慢速同步,但這可能不總是你想要的,因為雙方可能都已經有資料。"
-#: ../src/gtk-ui/sync-ui.c:1752
+#: ../src/gtk-ui/sync-ui.c:2791
+msgid "Failed to login. Could there be a problem with your username or password?"
+msgstr "登入失敗。你的使用者名稱或密碼是否有問題?"
+
+#: ../src/gtk-ui/sync-ui.c:2794
msgid "Forbidden"
msgstr "禁止"
-#: ../src/gtk-ui/sync-ui.c:1754
-msgid "Not found"
-msgstr "未找到"
+#: ../src/gtk-ui/sync-ui.c:2799
+msgid "The source could not be found. Could there be a problem with the server settings?"
+msgstr "無法找到來源。伺服器設定是否有問題?"
-#: ../src/gtk-ui/sync-ui.c:1756
+#: ../src/gtk-ui/sync-ui.c:2802
msgid "Fatal database error"
msgstr "致命數據錯誤"
-#: ../src/gtk-ui/sync-ui.c:1758
+#. This can happen when EDS is borked, restart it may help...
+#: ../src/gtk-ui/sync-ui.c:2805
+msgid "There is a problem with the local database. Syncing again or rebooting may help."
+msgstr "本機資料庫有問題。再次同步或是重新開機可能會有所幫助。"
+
+#: ../src/gtk-ui/sync-ui.c:2808
msgid "Database error"
msgstr "數據錯誤"
-#: ../src/gtk-ui/sync-ui.c:1760
+#: ../src/gtk-ui/sync-ui.c:2810
msgid "No space left"
msgstr "沒有空間"
-#. TODO identify problem item somehow ?
-#: ../src/gtk-ui/sync-ui.c:1763
+#: ../src/gtk-ui/sync-ui.c:2812
msgid "Failed to process SyncML"
msgstr "進行 SyncML 動作失敗"
-#: ../src/gtk-ui/sync-ui.c:1765
+#: ../src/gtk-ui/sync-ui.c:2814
msgid "Server authorization failed"
msgstr "伺服器授權失敗"
-#: ../src/gtk-ui/sync-ui.c:1767
+#: ../src/gtk-ui/sync-ui.c:2816
msgid "Failed to parse configuration file"
msgstr "解析設置檔案動作失敗"
-#: ../src/gtk-ui/sync-ui.c:1769
+#: ../src/gtk-ui/sync-ui.c:2818
msgid "Failed to read configuration file"
msgstr "讀取設置檔案動作失敗"
-#: ../src/gtk-ui/sync-ui.c:1771
+#: ../src/gtk-ui/sync-ui.c:2820
msgid "No configuration found"
msgstr "未找到設置"
-#: ../src/gtk-ui/sync-ui.c:1773
+#: ../src/gtk-ui/sync-ui.c:2822
msgid "No configuration file found"
msgstr "未找到設置檔案"
-#: ../src/gtk-ui/sync-ui.c:1775
+#: ../src/gtk-ui/sync-ui.c:2824
msgid "Server sent bad content"
-msgstr "伺服器發送出壞的內容"
-
-#: ../src/gtk-ui/sync-ui.c:1777
-msgid "Transport failure (no connection?)"
-msgstr "傳輸失敗(沒有連線?)"
+msgstr "伺服器傳送出壞的內容"
-#: ../src/gtk-ui/sync-ui.c:1779
-msgid "Connection timed out"
-msgstr "連線時間已過"
-
-#: ../src/gtk-ui/sync-ui.c:1781
+#: ../src/gtk-ui/sync-ui.c:2826
msgid "Connection certificate has expired"
msgstr "連線憑證己過期"
-#: ../src/gtk-ui/sync-ui.c:1783
+#: ../src/gtk-ui/sync-ui.c:2828
msgid "Connection certificate is invalid"
msgstr "連線憑證無效"
-#: ../src/gtk-ui/sync-ui.c:1786
-msgid "Connection failed"
-msgstr "連線失敗"
+#: ../src/gtk-ui/sync-ui.c:2836
+msgid "We were unable to connect to the server. The problem could be temporary or there could be something wrong with the server settings."
+msgstr "我們無法連接到伺服器。問題可能是暫時的,或是伺服器設定可能有問題。"
-#: ../src/gtk-ui/sync-ui.c:1788
+#: ../src/gtk-ui/sync-ui.c:2840
msgid "URL is bad"
msgstr "URL 不對"
-#: ../src/gtk-ui/sync-ui.c:1790
+#: ../src/gtk-ui/sync-ui.c:2842
msgid "Server not found"
msgstr "找不到伺服器"
-#: ../src/gtk-ui/sync-ui.c:1792
+#: ../src/gtk-ui/sync-ui.c:2844
#, c-format
msgid "Error %d"
msgstr "錯誤 %d"
-#. TODO show in UI: server disappeared
-#: ../src/gtk-ui/sync-ui.c:1803
-msgid "Syncevolution.Server D-Bus service exited unexpectedly"
-msgstr "Syncevlolution.Server 的 D-Bus 服務在沒有預料的情況下離開了"
-
-#: ../src/gtk-ui/sync-ui.c:1806
-msgid "Sync Failed"
-msgstr "同步失敗"
-
-#: ../src/gtk-ui/sync-ui-config.c:95
-#, c-format
-msgid "There was one remote rejection."
-msgid_plural "There were %d remote rejections."
-msgstr[0] "有一個遠端拒絕。"
-msgstr[1] "有 %d 個遠端拒絕。"
-
-#: ../src/gtk-ui/sync-ui-config.c:100
-#, c-format
-msgid "There was one local rejection."
-msgid_plural "There were %d local rejections."
-msgstr[0] "有一個本地拒絕。"
-msgstr[1] "有 %d 個本地拒絕。"
-
-#: ../src/gtk-ui/sync-ui-config.c:105
-#, c-format
-msgid "There were %d local rejections and %d remote rejections."
-msgstr "曾經有 %d 次本地拒絕和 %d 次遠端拒絕。"
-
-#: ../src/gtk-ui/sync-ui-config.c:110
-#, c-format
-msgid "Last time: No changes."
-msgstr "上次:沒有變更。"
-
-#: ../src/gtk-ui/sync-ui-config.c:112
-#, c-format
-msgid "Last time: Sent one change."
-msgid_plural "Last time: Sent %d changes."
-msgstr[0] "上一次:發送一個變更。"
-msgstr[1] "上一次:發送 %d 個變更。"
+#. title for the buttons on the right side of main view
+#: ../src/gtk-ui/ui.glade.h:2
+msgid "<b>Actions</b>"
+msgstr "<b>動作</b>"
-#. This is about changes made to the local data. Not all of these
-#. changes were requested by the remote server, so "applied"
-#. is a better word than "received" (bug #5185).
-#: ../src/gtk-ui/sync-ui-config.c:120
-#, c-format
-msgid "Last time: Applied one change."
-msgid_plural "Last time: Applied %d changes."
-msgstr[0] "上一次:套用了一個變更。"
-msgstr[1] "上一次:套用了 %d 個變更。"
+#. text between the two "start from scratch" buttons in emergency view
+#: ../src/gtk-ui/ui.glade.h:4
+msgid "<b>or</b>"
+msgstr "<b>或</b>"
-#: ../src/gtk-ui/sync-ui-config.c:125
-#, c-format
-msgid "Last time: Applied %d changes and sent %d changes."
-msgstr "上次:套用了 %d 個變更並傳送了 %d 個變更。"
+#: ../src/gtk-ui/ui.glade.h:5
+msgid "<big>Direct sync</big>"
+msgstr "<big>直接同步</big>"
-#: ../src/gtk-ui/ui.glade.h:1
-msgid "<b>Data</b>"
-msgstr "<b>資料</b>"
+#: ../src/gtk-ui/ui.glade.h:6
+msgid "<big>Network sync</big>"
+msgstr "<big>網路同步</big>"
-#: ../src/gtk-ui/ui.glade.h:2
-msgid "<b>No sync service in use</b>"
-msgstr "<b>沒有使用中的同步服務</b>"
+#. a title in emergency view
+#: ../src/gtk-ui/ui.glade.h:8
+msgid "<big>Restore from backup</big>"
+msgstr "<big>從備份還原</big>"
-#: ../src/gtk-ui/ui.glade.h:3
-msgid "<b>Sync failure</b>"
-msgstr "<b>同步失敗</b>"
+#. a title in emergency view
+#: ../src/gtk-ui/ui.glade.h:10
+msgid "<big>Slow sync</big>"
+msgstr "<big>慢速同步</big>"
-#: ../src/gtk-ui/ui.glade.h:4
-msgid "<b>Type of Sync</b>"
-msgstr "<b>同步的類型</b>"
+#. a title in emergency view
+#: ../src/gtk-ui/ui.glade.h:12
+msgid "<big>Start from scratch</big>"
+msgstr "<big>從零開始</big>"
-#: ../src/gtk-ui/ui.glade.h:5
-msgid "<big>Manual setup</big>"
-msgstr "<big>手動設置</big>"
+#: ../src/gtk-ui/ui.glade.h:13
+msgid ""
+"A slow sync compares items from both sides and tries to merge them. \n"
+"This may fail in some cases, leading to duplicates or lost information."
+msgstr ""
+"慢速同步會比較兩邊的項目,並嘗試合併它們。\n"
+"這在某些情況下可能會失敗,並導致副本產生或是遺失資訊。"
-#: ../src/gtk-ui/ui.glade.h:6
-msgid "<big>Supported services</big>"
-msgstr "<big>支援的服務</big>"
+#: ../src/gtk-ui/ui.glade.h:15
+msgid "Add new device"
+msgstr "加入新裝置"
-#: ../src/gtk-ui/ui.glade.h:7
+#: ../src/gtk-ui/ui.glade.h:16
msgid "Add new service"
msgstr "新增服務"
-#: ../src/gtk-ui/ui.glade.h:8
-msgid "Back to sync"
-msgstr "返回同步"
+#. explanation of "Restore backup" function
+#: ../src/gtk-ui/ui.glade.h:18
+msgid "Backups are made before every time we Sync. Choose a backup to restore. Any changes you have made since then will be lost."
+msgstr "在我們每次同步前都會進行備份。選擇要還原的備份。所有你從那時起的變更都會喪失。"
+
+#: ../src/gtk-ui/ui.glade.h:19
+msgid "Calendar"
+msgstr "行事曆"
-#: ../src/gtk-ui/ui.glade.h:9
+#. Button in main view, right side. Keep to below 20 chars per line, feel free to use two lines
+#: ../src/gtk-ui/ui.glade.h:21
msgid ""
-"Change sync\n"
-"service"
-msgstr "變更同步服務"
+"Change or edit\n"
+"sync service"
+msgstr ""
+"變更或編輯\n"
+"同步服務"
-#: ../src/gtk-ui/ui.glade.h:11
-msgid "Delete all local data and replace it with remote data"
-msgstr "刪除所有本地資料,並使用遠端資料取代"
+#: ../src/gtk-ui/ui.glade.h:23
+msgid ""
+"Delete all data on Zyb \n"
+"and replace with your\n"
+"local information"
+msgstr "刪除所有遠端資料,並使用本機資料取代"
-#: ../src/gtk-ui/ui.glade.h:12
-msgid "Delete all remote data and replace it with local data"
-msgstr "刪除所有遠端資料,並使用本地資料取代"
+#: ../src/gtk-ui/ui.glade.h:26
+msgid ""
+"Delete all your local\n"
+"information and replace\n"
+"with data from Zyb"
+msgstr "刪除所有本機資料,並使用遠端資料取代"
-#: ../src/gtk-ui/ui.glade.h:13
-msgid "Edit service settings"
-msgstr "編輯服務設定"
+#. button in main view, right side. Keep length to 20 characters or so, use two lines if needed
+#: ../src/gtk-ui/ui.glade.h:30
+msgid ""
+"Fix a sync\n"
+"emergency"
+msgstr ""
+"修正同步\n"
+"緊急狀況"
-#: ../src/gtk-ui/ui.glade.h:14
+#: ../src/gtk-ui/ui.glade.h:32
msgid ""
"If you don't see your service above but know that your sync provider uses SyncML\n"
"you can setup a service manually."
"如果你在上方沒有看到你的服務,但是你知道你的同步功能供應廠商使用 SyncML 的話,\n"
"你可以手動設定服務。"
-#: ../src/gtk-ui/ui.glade.h:16
-msgid "Merge local and remote data (recommended)"
-msgstr "合併本地和遠端資料(建議)"
-
-#: ../src/gtk-ui/ui.glade.h:17
-msgid "Select sync service"
-msgstr "選取同步服務"
-
-#: ../src/gtk-ui/ui.glade.h:18
-msgid ""
-"Sorry, you need an internet\n"
-"connection to sync."
-msgstr ""
-"抱歉,你需要有網際網路連線\n"
-"才能同步。"
+#: ../src/gtk-ui/ui.glade.h:34
+msgid "Settings"
+msgstr "設定"
-#: ../src/gtk-ui/ui.glade.h:22
-msgid "Sync settings"
-msgstr "同步設定"
+#: ../src/gtk-ui/ui.glade.h:37
+msgid "Sync Emergency"
+msgstr "同步緊急狀況"
-#: ../src/gtk-ui/ui.glade.h:23
-msgid "Synchronization is not available (D-Bus service does not answer), sorry."
-msgstr "非常抱歉,因為 D-Bus 服務沒有回應,所以無法提供同步化。"
-
-#: ../src/gtk-ui/ui.glade.h:24
+#: ../src/gtk-ui/ui.glade.h:39
msgid ""
"To sync you'll need a network connection and an account with a sync service.\n"
"We support the following services: "
msgstr ""
-"若要同步,你需要有網路連線以及使用同步服務的帳戶。\n"
+"若要同步,你需要有網路連線以及使用同步服務的帳號。\n"
"我們支援下列服務:"
-#: ../src/gtk-ui/ui.glade.h:26
-msgid ""
-"You haven't selected a sync service yet. Sync services let you \n"
-"synchronize your data between your netbook and a web service."
-msgstr "你尚未選取同步服務。同步服務讓你在你的網路筆電與網路服務之間同步你的資料。"
+#: ../src/gtk-ui/ui.glade.h:41
+msgid "Use Bluetooth to Sync your data from one device to another."
+msgstr "使用藍牙從某裝置同步你的資料到另一個裝置去。"
+
+#: ../src/gtk-ui/ui.glade.h:42
+msgid "You will need to add Bluetooth devices before they can be synced."
+msgstr "在它們能被同步前,你需要先加入藍牙裝置。"
#: ../src/gtk-ui/sync.desktop.in.h:2
#: ../src/gtk-ui/sync-gtk.desktop.in.h:2
msgid "Sync (GTK)"
msgstr "同步 (GTK)"
-#: ../src/gtk-ui/sync-config-widget.c:48
+#: ../src/gtk-ui/sync-config-widget.c:71
msgid "ScheduleWorld enables you to keep your contacts, events, tasks, and notes in sync."
msgstr "ScheduleWorld 可以讓你的連絡人、行事曆事項、工作、以及註記保持同步。"
-#: ../src/gtk-ui/sync-config-widget.c:51
-msgid "Google Sync can backup and synchronize your Address Book with your Gmail contacts."
-msgstr "Google Sync 可以讓你手中的通訊錄和 Gmail 連絡人進行備份以及同步。"
+#: ../src/gtk-ui/sync-config-widget.c:74
+msgid "Google Sync can backup and synchronize your contacts with your Gmail contacts."
+msgstr "Google Sync 可以將你的聯絡人和 Gmail 連絡人進行備份以及同步。"
#. TRANSLATORS: Please include the word "demo" (or the equivalent in
#. your language): Funambol is going to be a 90 day demo service
#. in the future
-#: ../src/gtk-ui/sync-config-widget.c:57
-msgid "Backup your contacts and calendar. Sync with a singleclick, anytime, anywhere (DEMO)."
+#: ../src/gtk-ui/sync-config-widget.c:80
+msgid "Backup your contacts and calendar. Sync with a single click, anytime, anywhere (DEMO)."
msgstr "備份你的連絡人與行事曆。一個按鍵就同步,任何時間、任何地點(樣本)。"
-#: ../src/gtk-ui/sync-config-widget.c:227
+#: ../src/gtk-ui/sync-config-widget.c:83
+msgid "Mobical Backup and Restore service allows you to securely backup your personal mobile data for free."
+msgstr "Mobical 備份與還原服務讓你可以安全地備份個人行動資料,而且免費。"
+
+#: ../src/gtk-ui/sync-config-widget.c:86
+msgid "ZYB is a simple way for people to store and share mobile information online."
+msgstr "ZYB 是人們儲存與線上分享行動資訊的一種簡單方法。"
+
+#: ../src/gtk-ui/sync-config-widget.c:89
+msgid "Memotoo lets you access your personal data from any computer connected to the Internet."
+msgstr "Memotoo 能讓你從任何連接到網路的電腦存取你的個人資料。"
+
+#: ../src/gtk-ui/sync-config-widget.c:255
+#, c-format
+msgid "Do you want to replace %s with %s? This will not remove any synced information on either end but you will no longer be able to sync with %s."
+msgstr "你想要把 %s 用 %s 取代掉嗎?這不會移除兩方任何同步過的資訊,但是你將無法再與 %s 進行同步。"
+
+#. TRANSLATORS: decline/accept buttons in warning dialog.
+#. Placeholder is service name
+#: ../src/gtk-ui/sync-config-widget.c:267
+#, c-format
+msgid "Yes, use %s"
+msgstr "是,使用 %s"
+
+#: ../src/gtk-ui/sync-config-widget.c:268
+#, c-format
+msgid "No, use %s"
+msgstr "是,使用 %s"
+
+#: ../src/gtk-ui/sync-config-widget.c:341
msgid "Service must have a name and server URL"
msgstr "服務項目必須要有一個名稱和伺服器網址"
-#: ../src/gtk-ui/sync-config-widget.c:271
+#: ../src/gtk-ui/sync-config-widget.c:381
+#, c-format
+msgid "Do you want to reset the settings for %s? This will not remove any synced information on either end."
+msgstr "你想要為 %s 重設設定嗎?這不會移除任何兩方同步過的資訊。"
+
+#. TRANSLATORS: buttons in reset-service warning dialog
+#: ../src/gtk-ui/sync-config-widget.c:385
+msgid "Yes, reset"
+msgstr "是,重設"
+
+#: ../src/gtk-ui/sync-config-widget.c:386
+#: ../src/gtk-ui/sync-config-widget.c:397
+msgid "No, keep settings"
+msgstr "不,維持設定"
+
+#: ../src/gtk-ui/sync-config-widget.c:391
+#, c-format
+msgid "Do you want to delete the settings for %s? This will not remove any synced information on either end but it will remove this service configuration."
+msgstr "你想要為 %s 刪除設定值嗎?這不會移除任何兩方同步過的資訊,但是它會移除本服務設定檔。"
+
+#. TRANSLATORS: buttons in delete-service warning dialog
+#: ../src/gtk-ui/sync-config-widget.c:396
+msgid "Yes, delete"
+msgstr "是,刪除"
+
+#: ../src/gtk-ui/sync-config-widget.c:425
msgid "Reset service"
msgstr "重設服務"
-#: ../src/gtk-ui/sync-config-widget.c:274
+#: ../src/gtk-ui/sync-config-widget.c:428
msgid "Delete service"
msgstr "刪除服務"
-#: ../src/gtk-ui/sync-config-widget.c:284
+#: ../src/gtk-ui/sync-config-widget.c:438
msgid "Save and use"
msgstr "儲存並使用"
-#: ../src/gtk-ui/sync-config-widget.c:287
+#: ../src/gtk-ui/sync-config-widget.c:441
msgid ""
"Save and replace\n"
"current service"
"儲存並取代\n"
"目前的服務"
-#. TRANSLATORS: label for an entry in service configuration.
-#. * Placeholder is a source name in settings window.
-#. * Example: "Addressbook URI"
-#: ../src/gtk-ui/sync-config-widget.c:355
+#. TRANSLATORS: label for an entry in service configuration form.
+#. * Placeholder is a source name.
+#. * Example: "Appointments URI"
+#: ../src/gtk-ui/sync-config-widget.c:672
#, c-format
msgid "%s URI"
msgstr "%s URI"
-#. TRANSLATORS: label of a entry in service configuration
-#: ../src/gtk-ui/sync-config-widget.c:419
-msgid "Server URL"
-msgstr "伺服器 URL"
+#. TRANSLATORS: toggles in service configuration form, placeholder is service
+#. * or device name
+#: ../src/gtk-ui/sync-config-widget.c:850
+#, c-format
+msgid "Send changes to %s"
+msgstr "傳送變更到 %s"
-#. TRANSLATORS: this is the epander label for server settings
-#: ../src/gtk-ui/sync-config-widget.c:459
-msgid "Hide server settings"
-msgstr "隱藏伺服器設定"
+#: ../src/gtk-ui/sync-config-widget.c:854
+#, c-format
+msgid "Receive changes from %s"
+msgstr "接收來自 %s 的變更"
-#: ../src/gtk-ui/sync-config-widget.c:461
-msgid "Show server settings"
-msgstr "顯示伺服器設定"
+#: ../src/gtk-ui/sync-config-widget.c:869
+msgid "<b>Sync</b>"
+msgstr "<b>同步</b>"
+
+#. TRANSLATORS: label of a entry in service configuration
+#: ../src/gtk-ui/sync-config-widget.c:885
+msgid "Server address"
+msgstr "伺服器位址"
+
+#: ../src/gtk-ui/sync-config-widget.c:1067
+#, c-format
+msgid "%s - Bluetooth device"
+msgstr "%s - 藍牙裝置"
#. TRANSLATORS: service title for services that are not based on a
#. * template in service list, the placeholder is the name of the service
-#: ../src/gtk-ui/sync-config-widget.c:512
+#: ../src/gtk-ui/sync-config-widget.c:1073
#, c-format
msgid "%s - manually setup"
msgstr "%s - 手動設置"
-#. TRANSLATORS: linkbutton label
-#: ../src/gtk-ui/sync-config-widget.c:1189
+#. TRANSLATORS: link button in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1748
msgid "Launch website"
msgstr "開啟網站"
-#. TRANSLATORS: button label
-#: ../src/gtk-ui/sync-config-widget.c:1198
+#. TRANSLATORS: button in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1757
msgid "Setup now"
msgstr "立刻設置"
-#. TRANSLATORS: labels of entries
-#: ../src/gtk-ui/sync-config-widget.c:1236
+#. TRANSLATORS: labels of entries in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1820
msgid "Username"
msgstr "使用者名稱"
-#: ../src/gtk-ui/sync-config-widget.c:1251
+#: ../src/gtk-ui/sync-config-widget.c:1835
msgid "Password"
msgstr "密碼"
-#: ../src/gtk-ui/sync-config-widget.c:1295
+#. TRANSLATORS: warning in service configuration form for people
+#. who have modified the configuration via other means.
+#: ../src/gtk-ui/sync-config-widget.c:1858
+msgid "Current service configuration is more complex than what can be shown here. Changes to sync mode or synced data types will overwrite that configuration."
+msgstr "目前的服務設定檔比這裡能夠顯示的還要複雜許多。變更為同步模式或是同步過的資料類型將會覆蓋寫入那份設定檔。"
+
+#. TRANSLATORS: this is the epander label for server settings
+#. in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1877
+msgid "Hide server settings"
+msgstr "隱藏伺服器設定"
+
+#. TRANSLATORS: this is the epander label for server settings
+#. in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1897
+msgid "Show server settings"
+msgstr "顯示伺服器設定"
+
+#. TRANSLATORS: button in service configuration form
+#: ../src/gtk-ui/sync-config-widget.c:1910
msgid "Stop using service"
msgstr "停止使用服務"
+#: ../src/gnome-bluetooth/syncevolution.c:110
+msgid "Sync in the Sync application"
+msgstr "在「同步」應用程式內同步"
+
+#~ msgid "Todo"
+#~ msgstr "要做的事"
+#~ msgid "Memo"
+#~ msgstr "備忘錄"
+#~ msgid "Failed to abort sync"
+#~ msgstr "放棄同步時失敗"
+#~ msgid "Failed to start sync"
+#~ msgstr "開始同步動作失敗"
+#~ msgid "%s (not supported by this service)"
+#~ msgstr "%s (不被此服務支援)"
+#~ msgid "Failed to get list of configured services from SyncEvolution"
+#~ msgstr "從 SyncEvolution 取得已設定的服務清單時失敗"
+#~ msgid "Not authorized"
+#~ msgstr "未授權"
+#~ msgid "Not found"
+#~ msgstr "未找到"
+#~ msgid "Transport failure (no connection?)"
+#~ msgstr "傳輸失敗(沒有連線?)"
+#~ msgid "Connection timed out"
+#~ msgstr "連線時間已過"
+#~ msgid "Connection failed"
+#~ msgstr "連線失敗"
+#~ msgid "Syncevolution.Server D-Bus service exited unexpectedly"
+#~ msgstr "Syncevlolution.Server 的 D-Bus 服務在沒有預料的情況下離開了"
+#~ msgid "<b>No sync service in use</b>"
+#~ msgstr "<b>沒有使用中的同步服務</b>"
+#~ msgid "<big>Manual setup</big>"
+#~ msgstr "<big>手動設置</big>"
+#~ msgid "Merge local and remote data (recommended)"
+#~ msgstr "合併本地和遠端資料(建議)"
+#~ msgid ""
+#~ "Sorry, you need an internet\n"
+#~ "connection to sync."
+#~ msgstr ""
+#~ "抱歉,你需要有網際網路連線\n"
+#~ "才能同步。"
+#~ msgid ""
+#~ "Synchronization is not available (D-Bus service does not answer), sorry."
+#~ msgstr "非常抱歉,因為 D-Bus 服務沒有回應,所以無法提供同步化。"
+#~ msgid "Server URL"
+#~ msgstr "伺服器 URL"
#~ msgid "Addressbook"
#~ msgstr "地址簿"
#~ msgid "Failed to save current service in GConf configuration system"
#~ msgstr "正在結束同步"
#~ msgid "Reset original server settings"
#~ msgstr "重置為原始的伺服器設定"
-#~ msgid "Service name"
-#~ msgstr "服務名稱"
#~ msgid "Bring your data with you"
#~ msgstr "請帶攜你的數據"
endif
SUBDIRS = $(SYNTHESIS_SUBDIR) $(DBUS_DIRS) syncevo $(BACKENDS) $(GUI_DIR)
-DIST_SUBDIRS = gdbus dbus syncevo $(BACKENDS) gtk-ui
+if ENABLE_GNOME_BLUETOOTH_PANEL
+SUBDIRS += gnome-bluetooth
+endif
+DIST_SUBDIRS = gdbus dbus syncevo $(BACKENDS) gtk-ui gnome-bluetooth
BUILT_SOURCES =
AM_CPPFLAGS = $(SUBDIRS:%=-I$(srcdir)/%) -I$(srcdir)/../test -I$(top_srcdir) $(BACKEND_CPPFLAGS)
SYNCEVOLUTION_LDADD += $(SYNCSOURCES)
SYNCEVOLUTION_DEP += $(SYNCSOURCES)
endif
-EXTRA_DIST = shlibs.local Makefile-gen.am syncclient_sample_config.xml $(service_in_files)
+EXTRA_DIST = shlibs.local Makefile-gen.am $(service_in_files)
TEMPLATE_FILES = @TEMPLATE_FILES@
templatedir = $(datadir)/syncevolution/
endif
SUBDIRS = $(SYNTHESIS_SUBDIR) $(DBUS_DIRS) syncevo $(BACKENDS) $(GUI_DIR)
-DIST_SUBDIRS = gdbus dbus syncevo $(BACKENDS) gtk-ui
+if ENABLE_GNOME_BLUETOOTH_PANEL
+SUBDIRS += gnome-bluetooth
+endif
+DIST_SUBDIRS = gdbus dbus syncevo $(BACKENDS) gtk-ui gnome-bluetooth
BUILT_SOURCES =
AM_CPPFLAGS = $(SUBDIRS:%=-I$(srcdir)/%) -I$(srcdir)/../test -I$(top_srcdir) $(BACKEND_CPPFLAGS)
SYNCEVOLUTION_LDADD += $(SYNCSOURCES)
SYNCEVOLUTION_DEP += $(SYNCSOURCES)
endif
-EXTRA_DIST = shlibs.local Makefile-gen.am syncclient_sample_config.xml $(service_in_files)
+EXTRA_DIST = shlibs.local Makefile-gen.am $(service_in_files)
TEMPLATE_FILES = templates/README templates/servers/Funambol/config.ini templates/servers/Funambol/template.ini templates/servers/Funambol/sources/calendar/config.ini templates/servers/Funambol/sources/todo/config.ini templates/servers/Funambol/sources/addressbook/config.ini templates/servers/Funambol/sources/memo/config.ini templates/servers/ScheduleWorld/config.ini templates/servers/ScheduleWorld/template.ini templates/servers/ScheduleWorld/sources/calendar/config.ini templates/servers/ScheduleWorld/sources/todo/config.ini templates/servers/ScheduleWorld/sources/addressbook/config.ini templates/servers/ScheduleWorld/sources/memo/config.ini templates/clients/phone/nokia/S40/7210c/config.ini templates/clients/phone/nokia/S40/7210c/template.ini templates/clients/phone/nokia/S40/7210c/sources/calendar/config.ini templates/clients/phone/nokia/S40/7210c/sources/calendar+todo/config.ini templates/clients/phone/nokia/S40/7210c/sources/todo/config.ini templates/clients/phone/nokia/S40/7210c/sources/addressbook/config.ini templates/clients/phone/nokia/S40/7210c/sources/memo/config.ini templates/clients/default/template.ini templates/clients/SyncEvolution/config.ini templates/clients/SyncEvolution/template.ini templates/clients/SyncEvolution/sources/calendar/config.ini templates/clients/SyncEvolution/sources/todo/config.ini templates/clients/SyncEvolution/sources/addressbook/config.ini templates/clients/SyncEvolution/sources/memo/config.ini
templatedir = $(datadir)/syncevolution/
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+@ENABLE_GNOME_BLUETOOTH_PANEL_TRUE@am__append_1 = gnome-bluetooth
EXTRA_PROGRAMS = $(am__EXEEXT_1) abort-redirect$(EXEEXT)
TESTS = $(am__EXEEXT_2)
bin_PROGRAMS = syncevolution$(EXEEXT) $(am__EXEEXT_2)
@COND_DBUS_TRUE@libexec_PROGRAMS = syncevo-dbus-server$(EXEEXT)
-@ENABLE_MODULES_FALSE@am__append_1 = $(SYNCSOURCES)
@ENABLE_MODULES_FALSE@am__append_2 = $(SYNCSOURCES)
-@ENABLE_MODULES_TRUE@am__append_3 = $(BACKEND_REGISTRIES)
-@ENABLE_MODULES_FALSE@am__append_4 = $(BACKEND_REGISTRIES)
+@ENABLE_MODULES_FALSE@am__append_3 = $(SYNCSOURCES)
+@ENABLE_MODULES_TRUE@am__append_4 = $(BACKEND_REGISTRIES)
+@ENABLE_MODULES_FALSE@am__append_5 = $(BACKEND_REGISTRIES)
# distribute test system?
# yes: install client-test in bindir, test files in datadir
-@ENABLE_TESTING_TRUE@am__append_5 = client-test
@ENABLE_TESTING_TRUE@am__append_6 = client-test
+@ENABLE_TESTING_TRUE@am__append_7 = 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_7 = client-test
-@ENABLE_TESTING_FALSE@am__append_8 = $(CLIENT_LIB_TEST_FILES)
-@ENABLE_TESTING_FALSE@am__append_9 = all
+@ENABLE_TESTING_FALSE@am__append_8 = client-test
+@ENABLE_TESTING_FALSE@am__append_9 = $(CLIENT_LIB_TEST_FILES)
+@ENABLE_TESTING_FALSE@am__append_10 = all
subdir = src
DIST_COMMON = $(am__nobase_dist_doc_DATA_DIST) \
$(nobase_dist_template_DATA) $(srcdir)/Makefile.am \
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
STABLE_VERSION = @STABLE_VERSION@
STRIP = @STRIP@
SYNCEVOLUTION_CXXFLAGS = @SYNCEVOLUTION_CXXFLAGS@
-SYNCEVOLUTION_LDADD = @SYNCEVOLUTION_LDADD@ $(am__append_1)
+SYNCEVOLUTION_LDADD = @SYNCEVOLUTION_LDADD@ $(am__append_2)
SYNCEVOLUTION_LOCALEDIR = @SYNCEVOLUTION_LOCALEDIR@
SYNCSOURCES = @SYNCSOURCES@
SYNTHESIS = @SYNTHESIS@
@COND_DBUS_FALSE@@COND_GUI_TRUE@DBUS_DIRS = dbus/interfaces
@COND_DBUS_TRUE@DBUS_DIRS = gdbus dbus
@COND_GUI_TRUE@GUI_DIR = gtk-ui
-SUBDIRS = $(SYNTHESIS_SUBDIR) $(DBUS_DIRS) syncevo $(BACKENDS) $(GUI_DIR)
-DIST_SUBDIRS = gdbus dbus syncevo $(BACKENDS) gtk-ui
+SUBDIRS = $(SYNTHESIS_SUBDIR) $(DBUS_DIRS) syncevo $(BACKENDS) \
+ $(GUI_DIR) $(am__append_1)
+DIST_SUBDIRS = gdbus dbus syncevo $(BACKENDS) gtk-ui gnome-bluetooth
BUILT_SOURCES =
AM_CPPFLAGS = $(SUBDIRS:%=-I$(srcdir)/%) -I$(srcdir)/../test -I$(top_srcdir) $(BACKEND_CPPFLAGS)
bin_SCRIPTS = synccompare
-SYNCEVOLUTION_DEP = $(am__append_2)
-EXTRA_DIST = shlibs.local Makefile-gen.am syncclient_sample_config.xml \
- $(service_in_files) $(am__append_3)
+SYNCEVOLUTION_DEP = $(am__append_3)
+EXTRA_DIST = shlibs.local Makefile-gen.am $(service_in_files) \
+ $(am__append_4)
TEMPLATE_FILES = templates/README \
templates/servers/Funambol/config.ini \
templates/servers/Funambol/template.ini \
MAINTAINERCLEANFILES = Makefile.in
CLEANFILES = libstdc++.a client-test $(CLIENT_LIB_TEST_FILES) \
org.syncevolution.service abort-redirect.log
-CORE_SOURCES = $(am__append_4)
+CORE_SOURCES = $(am__append_5)
# The files which register backends have to be compiled into
# "client-test" and "syncevolution" in order to pull in the
../test/client-test-main.cpp \
$(CORE_SOURCES)
-nodist_client_test_SOURCES = ../test/test.cpp $(am__append_8)
+nodist_client_test_SOURCES = ../test/test.cpp $(am__append_9)
# list of test file base files
#
# runs the binary with out-dated auxiliary files.
client_test_DEPENDENCIES = $(EXTRA_LTLIBRARIES) $(CORE_DEP) \
$(CLIENT_LIB_TEST_FILES) testcase2patch synccompare templates \
- $(am__append_9)
+ $(am__append_10)
@ENABLE_TESTING_TRUE@nobase_dist_doc_DATA = $(CLIENT_LIB_TEST_FILES)
abort_redirect_SOURCES = ../test/abort-redirect.cpp
abort_redirect_CPPFLAGS = -DHAVE_CONFIG_H $(AM_CPPFLAGS)
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
(void *)"Evolution Data Server has died unexpectedly, database no longer available.");
}
+bool EvolutionCalendarSource::isEmpty()
+{
+ // TODO: add more efficient implementation which does not
+ // depend on actually pulling all items from EDS
+ RevisionMap_t revisions;
+ listAllItems(revisions);
+ return revisions.empty();
+}
+
void EvolutionCalendarSource::listAllItems(RevisionMap_t &revisions)
{
GError *gerror = NULL;
}
}
m_allLUIDs.erase(luid);
+
+ if (!id.m_rid.empty()) {
+ // Removing the child may have modified the parent.
+ // We must record the new LAST-MODIFIED string,
+ // otherwise it might be reported as modified during
+ // the next sync (timing dependent: if the parent
+ // was updated before removing the child *and* the
+ // update and remove fall into the same second,
+ // then the modTime does not change again during the
+ // removal).
+ try {
+ ItemID parent(id.m_uid, "");
+ string modTime = getItemModTime(parent);
+ string parentLUID = parent.getLUID();
+ updateRevision(getTrackingNode(), parentLUID, parentLUID, modTime);
+ } catch (...) {
+ // There's no guarantee that the parent still exists.
+ // Instead of checking that, ignore errors (a bit hacky,
+ // but better than breaking the removal).
+ }
+ }
}
icalcomponent *EvolutionCalendarSource::retrieveItem(const ItemID &id)
//
virtual Databases getDatabases();
virtual void open();
+ virtual bool isEmpty();
virtual void close();
virtual const char *getMimeType() const { return "text/calendar"; }
virtual const char *getMimeVersion() const { return "2.0"; }
isMe = sourceType.m_backend == "Evolution Task List";
if (isMe || sourceType.m_backend == "todo") {
- if (sourceType.m_format == "" || sourceType.m_format == "text/calendar"
- || sourceType.m_format == "text/x-vcalendar") {
+ if (sourceType.m_format == "" ||
+ sourceType.m_format == "text/calendar" ||
+ sourceType.m_format == "text/x-calendar" ||
+ sourceType.m_format == "text/x-vcalendar") {
return
#ifdef ENABLE_ECAL
enabled ? new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_TODO, params) :
isMe = sourceType.m_backend == "Evolution Calendar";
if (isMe || sourceType.m_backend == "calendar") {
- if (sourceType.m_format == "" || sourceType.m_format == "text/calendar" ||
- sourceType.m_format == "text/x-vcalendar" /* this is for backwards compatibility with broken configs */ ) {
+ if (sourceType.m_format == "" ||
+ sourceType.m_format == "text/calendar" ||
+ sourceType.m_format == "text/x-calendar" ||
+ sourceType.m_format == "text/x-vcalendar") {
return
#ifdef ENABLE_ECAL
enabled ? new EvolutionCalendarSource(E_CAL_SOURCE_TYPE_EVENT, params) :
createSource,
"Evolution Calendar = calendar = events = evolution-events\n"
" iCalendar 2.0 (default) = text/calendar\n"
- " vCalendar 1.0 = text/x-calendar\n"
+ " vCalendar 1.0 = text/x-vcalendar\n"
"Evolution Task List = Evolution Tasks = todo = tasks = evolution-tasks\n"
" iCalendar 2.0 (default) = text/calendar\n"
- " vCalendar 1.0 = text/x-calendar\n"
+ " vCalendar 1.0 = text/x-vcalendar\n"
"Evolution Memos = memo = memos = evolution-memos\n"
" plain text in UTF-8 (default) = text/plain\n"
" iCalendar 2.0 = text/calendar\n"
- " vCalendar 1.0 = text/x-calendar\n"
+ " vCalendar 1.0 = text/x-vcalendar\n"
" The later format is not tested because none of the\n"
" supported SyncML servers accepts it.\n",
Values() +
Databases secondary;
Databases result;
- bool first = true;
for (GSList *g = e_source_list_peek_groups (sources); g; g = g->next) {
ESourceGroup *group = E_SOURCE_GROUP (g->data);
for (GSList *s = e_source_group_peek_sources (group); s; s = s->next) {
}
Database entry(e_source_peek_name(source),
uristr,
- first);
+ false);
if (boost::starts_with(uristr, "couchdb://")) {
// Append CouchDB address books at the end of the list,
// otherwise preserving the order of address books.
} else {
result.push_back(entry);
}
- first = false;
}
}
result.insert(result.end(), secondary.begin(), secondary.end());
const char *uri = e_book_get_uri (book);
result.push_back(Database(name, uri, true));
}
+ } else {
+ // the first DB found is the default
+ result[0].m_isDefault = true;
}
return result;
(void *)"Evolution Data Server has died unexpectedly, contacts no longer available.");
}
+bool EvolutionContactSource::isEmpty()
+{
+ // TODO: add more efficient implementation which does not
+ // depend on actually pulling all items from EDS
+ RevisionMap_t revisions;
+ listAllItems(revisions);
+ return revisions.empty();
+}
void EvolutionContactSource::listAllItems(RevisionMap_t &revisions)
{
//
virtual Databases getDatabases();
virtual void open();
+ virtual bool isEmpty();
virtual void close();
virtual const char *getMimeType() const;
virtual const char *getMimeVersion() const;
*/
#include "EvolutionSyncSource.h"
+#include <syncevo/SmartPtr.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
ESource *EvolutionSyncSource::findSource( ESourceList *list, const string &id )
{
+ string finalID;
+ if (!id.empty()) {
+ finalID = id;
+ } else {
+ // Nothing selected specifically, use the one marked as default
+ // by the backend. If none is marked, use the first one
+ // (not expected to happen, though).
+ BOOST_FOREACH(const Database &db, getDatabases()) {
+ if (db.m_isDefault) {
+ finalID = db.m_uri;
+ break;
+ }
+ }
+ }
+
for (GSList *g = e_source_list_peek_groups (list); g; g = g->next) {
ESourceGroup *group = E_SOURCE_GROUP (g->data);
GSList *s;
for (s = e_source_group_peek_sources (group); s; s = s->next) {
ESource *source = E_SOURCE (s->data);
- char *uri = e_source_get_uri(source);
- bool found = id.empty() ||
- !id.compare(e_source_peek_name(source)) ||
- (uri && !id.compare(uri));
- g_free(uri);
+ GString uri(e_source_get_uri(source));
+ bool found = finalID.empty() ||
+ !finalID.compare(e_source_peek_name(source)) ||
+ (uri && !finalID.compare(uri));
if (found) {
return source;
}
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
ECAL_LIBS=
fi
+PKG_CHECK_MODULES(LIBICAL_AVAILABLE,
+ libical >= 0.43,
+ AC_DEFINE(HAVE_LIBICAL_R, 1, [have recent enough libical with _r variants]),
+ pass)
+
if test "$enable_evo" = "yes"; then
need_glib="yes"
if test "$EDSFOUND" = "yes"; then
*/
#include "libical/icalstrdup.h"
+#include <syncevo/eds_abi_wrapper.h>
#if !defined(LIBICAL_MEMFIXES) || defined(EVOLUTION_COMPATIBILITY)
char *ical_strdup(const char *x)
{
#ifdef LIBICAL_RUNTIME_CHECK
+ // One situation when we must not dup strings is when
+ // running with a libecal with the modified string
+ // handling semantic. Check that here.
static enum {
PATCH_UNCHECKED,
PATCH_FOUND,
}
#endif
+#ifdef EVOLUTION_COMPATIBILITY
+ // Another situation is when we have a libical with the
+ // _r variants of the relevant calls. We can call that directly,
+ // which has the advantage that we get the saner implementation.
+ // There have been crashes on Debian testing with libical 0.43-2
+ // inside icalmemory_add_tmp_buffer/icaltime_as_ical_string.
+ //
+ // We assume here that if one _r variant was found, all of
+ // them are found. See also the wrappers in eds_abi_wrapper.h.
+ if (EDSAbiWrapperSingleton.icalcomponent_as_ical_string_r) {
+ return (char *)x;
+ }
+#endif
+
return x ? strdup(x) : NULL;
}
#endif
#include <libical/ical.h>
+#include <syncevo/eds_abi_wrapper.h>
+
#ifdef __cplusplus
extern "C" {
#pragma }
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <dirent.h>
#include <syncevo/util.h>
#include <sstream>
#include <fstream>
+#include <syncevo/SyncContext.h>
#include <syncevo/declarations.h>
SE_BEGIN_CXX
m_basedir = basedir;
}
+bool FileSyncSource::isEmpty()
+{
+ DIR *dir = NULL;
+ bool empty = true;
+
+ try {
+ dir = opendir(m_basedir.c_str());
+ if (!dir) {
+ SyncContext::throwError(m_basedir, errno);
+ }
+ errno = 0;
+ struct dirent *entry = readdir(dir);
+ while (entry) {
+ if (strcmp(entry->d_name, ".") &&
+ strcmp(entry->d_name, "..")) {
+ empty = false;
+ break;
+ }
+ entry = readdir(dir);
+ }
+ if (errno) {
+ SyncContext::throwError(m_basedir, errno);
+ }
+ } catch(...) {
+ if (dir) {
+ closedir(dir);
+ }
+ throw;
+ }
+
+ closedir(dir);
+ return empty;
+}
+
void FileSyncSource::close()
{
m_basedir.clear();
protected:
/* implementation of SyncSource interface */
virtual void open();
+ virtual bool isEmpty();
virtual void close();
virtual Databases getDatabases();
virtual const char *getMimeType() const;
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
conv->setSyncing(true); // not sure what this does, but may as well tell the truth
}
+bool MaemoCalendarSource::isEmpty()
+{
+ // TODO: provide a real implementation. Always returning false
+ // here disables the "allow slow sync when no local data" heuristic
+ // for preventSlowSync=1.
+ return false;
+}
+
void MaemoCalendarSource::close()
{
delete conv;
protected:
/* implementation of SyncSource interface */
virtual void open();
+ virtual bool isEmpty();
virtual void close();
virtual Databases getDatabases();
virtual const char *getMimeType() const;
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
return result;
}
+bool SQLiteContactSource::isEmpty()
+{
+ // there are probably more efficient ways to do this, but this is just
+ // a proof-of-concept anyway
+ sqliteptr all(m_sqlite.prepareSQL("SELECT ROWID FROM ABPerson;"));
+ while (m_sqlite.checkSQL(sqlite3_step(all)) == SQLITE_ROW) {
+ return false;
+ }
+ return true;
+}
+
void SQLiteContactSource::listAllItems(RevisionMap_t &revisions)
{
sqliteptr all(m_sqlite.prepareSQL("SELECT ROWID, CreationDate, ModificationDate FROM ABPerson;"));
SyncSourceRevisions::init(NULL, NULL, 1, m_operations);
SyncSourceChanges::init(m_operations);
+ m_operations.m_isEmpty = boost::bind(&SQLiteContactSource::isEmpty, this);
m_operations.m_readItemAsKey = boost::bind(&SQLiteContactSource::readItemAsKey, this, _1, _2);
m_operations.m_insertItemAsKey = boost::bind(&SQLiteContactSource::insertItemAsKey, this, _1, (sysync::cItemID)NULL, _2);
m_operations.m_updateItemAsKey = boost::bind(&SQLiteContactSource::insertItemAsKey, this, _1, _2, _3);
/** encapsulates access to database */
boost::shared_ptr<ConfigNode> m_trackingNode;
SQLiteUtil m_sqlite;
+
+ /** implements the m_isEmpty operation */
+ bool isEmpty();
};
#endif // ENABLE_SQLITE
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
{
}
+bool XMLRPCSyncSource::isEmpty()
+{
+ // TODO: provide a real implementation. Always returning false
+ // here disables the "allow slow sync when no local data" heuristic
+ // for preventSlowSync=1.
+ return false;
+}
+
void XMLRPCSyncSource::close()
{
}
protected:
/* implementation of SyncSource interface */
virtual void open();
+ virtual bool isEmpty();
virtual void close();
virtual Databases getDatabases();
virtual const char *getMimeType() const;
" xmlrpc:text/plain:1.0\n"
" xmlrpc:text/x-vcard:2.1\n"
" xmlrpc:text/vcard:3.0\n"
- " xmlrpc:text/x-calendar:1.0\n"
+ " xmlrpc:text/x-vcalendar:1.0\n"
" xmlrpc:text/calendar:2.0\n",
Values() +
(Aliases("XMLRPC interface") + "xmlrpc"));
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
VOID:STRING,STRING
VOID:STRING,BOOLEAN
VOID:STRING,STRING,STRING
-VOID:STRING,STRING,STRING,STRING,STRING
+VOID:STRING,STRING,STRING,STRING,STRING,BOXED
VOID:INT,BOXED
VOID:UINT,UINT,BOXED
<method name ="GetConfigs">
<doc:doc><doc:description>
Get an array of all configured servers (or templates)
+
+ In getting templates mode, the dbus server checks the paired devices
+ from bluez and returns the matched templates. Templates for each device
+ are re-named with 'Bluetooth_<mac address>_<number>', where number
+ enumerates the templates created for the device.
+
+ Get these templates latter when calling GetConfig with additional new
+ properties:
+ description - the description for the template
+ score - the calculated score based on the device name and template
+ deviceName - the device name that the template is for
+ fingerPrint - the fingerPrint of the template, used for dbus
+ clients to re-match with user input device info
+ Also a property value is changed: 'syncURL' is replaced with the device
+ mac address.
</doc:description></doc:doc>
<arg type="b" name="template" direction="in">
<doc:doc><doc:summary>
</arg>
</signal>
+ <signal name="TemplatesChanged">
+ <doc:doc>
+ <doc:description>
+ Template added or removed, for example because a Bluetooth
+ peer was paired resp. removed. To find out more, request
+ list of templates anew.
+ </doc:description>
+ </doc:doc>
+ </signal>
+
<signal name="Presence">
<doc:doc>
<doc:description>
g_return_val_if_fail (config, FALSE);
g_return_val_if_fail (value, FALSE);
+ *value = NULL;
+
if (!source || strlen (source) == 0) {
name = g_strdup ("");
} else {
g_free (name);
if (source_config) {
- *value = (char*)g_hash_table_lookup (source_config, key);
- return TRUE;
+ return g_hash_table_lookup_extended (source_config, key,
+ NULL, (gpointer*)value);
}
-
return FALSE;
}
syncevo_config_free (SyncevoConfig *config)
{
/* NOTE: Hashtables gcreated by dbus-glib should free their contents */
- g_hash_table_destroy (config);
+ if (config) {
+ g_hash_table_destroy (config);
+ }
}
const char*
status = SYNCEVO_STATUS_UNKNOWN;
}
+ if (status_str && strstr (status_str, ";waiting")) {
+ status |= SYNCEVO_STATUS_WAITING;
+ }
+
return status;
}
SyncevoSyncMode
syncevo_sync_mode_from_string (const char *mode_str)
{
- if (!mode_str) {
- return SYNCEVO_SYNC_UNKNOWN;
- } else if (g_str_has_prefix (mode_str, "none") ||
- g_str_has_prefix (mode_str, "disabled")) {
+ if (!mode_str ||
+ g_str_has_prefix (mode_str, "none") ||
+ g_str_has_prefix (mode_str, "disabled")) {
return SYNCEVO_SYNC_NONE;
} else if (g_str_has_prefix (mode_str, "two-way")) {
return SYNCEVO_SYNC_TWO_WAY;
}
}
-static SyncevoSourceStatus
+static SyncevoSessionStatus
syncevo_source_status_from_string (const char *status_str)
{
- SyncevoSourceStatus status;
+ SyncevoSessionStatus status;
if (!status_str) {
- status = SYNCEVO_SOURCE_UNKNOWN;
+ status = SYNCEVO_STATUS_UNKNOWN;
} else if (g_str_has_prefix (status_str, "idle")) {
- status = SYNCEVO_SOURCE_IDLE;
+ status = SYNCEVO_STATUS_IDLE;
} else if (g_str_has_prefix (status_str, "running")) {
- status = SYNCEVO_SOURCE_RUNNING;
+ status = SYNCEVO_STATUS_RUNNING;
} else if (g_str_has_prefix (status_str, "done")) {
- status = SYNCEVO_SOURCE_DONE;
+ status = SYNCEVO_STATUS_DONE;
} else {
- status = SYNCEVO_SOURCE_UNKNOWN;
+ status = SYNCEVO_STATUS_UNKNOWN;
}
/* check modifiers */
if (status_str && strstr (status_str, ";waiting")) {
- status |= SYNCEVO_SOURCE_WAITING;
+ status |= SYNCEVO_STATUS_WAITING;
}
return status;
const char *mode_str;
const char *status_str;
SyncevoSyncMode mode;
- SyncevoSourceStatus status;
+ SyncevoSessionStatus status;
guint error_code;
mode_str = g_value_get_string (g_value_array_get_nth (source_status, 0));
g_hash_table_destroy (source_statuses);
}
-/* The return value contents are only valid as long as the
- * SyncevoSourceProgresses is. */
-SyncevoSourceProgress*
-syncevo_source_progresses_get_current (SyncevoSourceProgresses *source_progresses)
+void
+syncevo_source_progresses_foreach (SyncevoSourceProgresses *source_progresses,
+ SourceProgressFunc func,
+ gpointer userdata)
{
const char *phase_str, *name;
GHashTableIter iter;
GValueArray *progress_array;
- GValue *val;
- SyncevoSourceProgress *progress = NULL;
- g_return_val_if_fail (source_progresses, FALSE);
+ g_return_if_fail (source_progresses);
g_hash_table_iter_init (&iter, source_progresses);
while (g_hash_table_iter_next (&iter, (gpointer)&name, (gpointer)&progress_array)) {
SyncevoSourcePhase phase;
- phase_str = g_value_get_string (g_value_array_get_nth (progress_array, 0));
+ phase_str = g_value_get_string (g_value_array_get_nth (progress_array, 0));
if (!phase_str) {
phase = SYNCEVO_PHASE_NONE;
phase = SYNCEVO_PHASE_NONE;
}
- if (phase == SYNCEVO_PHASE_NONE) {
- continue;
- }
-
- progress = g_slice_new (SyncevoSourceProgress);
- progress->name = g_strdup (name);
- progress->phase = phase;
-
+/*
val = g_value_array_get_nth (progress_array, 1);
progress->prepare_current = g_value_get_int (val);
val = g_value_array_get_nth (progress_array, 2);
progress->receive_current = g_value_get_int (val);
val = g_value_array_get_nth (progress_array, 6);
progress->receive_total = g_value_get_int (val);
+*/
- break;
+ func (name, phase, userdata);
}
- return progress;
}
-void
-syncevo_source_progress_free (SyncevoSourceProgress *progress)
-{
- g_free (progress->name);
- g_slice_free (SyncevoSourceProgress, progress);
-}
static void
free_source_progress_item (char *source,
GValueArray *progress_array)
SYNCEVO_SYNC_ONE_WAY_FROM_SERVER,
} SyncevoSyncMode;
+/* SyncevoSessionStatus is a bitfield, although most value are exclusive */
typedef enum {
- SYNCEVO_STATUS_UNKNOWN,
- SYNCEVO_STATUS_QUEUEING,
- SYNCEVO_STATUS_IDLE,
- SYNCEVO_STATUS_RUNNING,
- SYNCEVO_STATUS_ABORTING,
- SYNCEVO_STATUS_SUSPENDING,
- SYNCEVO_STATUS_DONE,
-} SyncevoSessionStatus;
-
-
-/* SyncevoSourceStatus is a bitfield, but only one of four first values
- * will be present */
-typedef enum {
- SYNCEVO_SOURCE_UNKNOWN = 0,
- SYNCEVO_SOURCE_IDLE = 1 << 0,
- SYNCEVO_SOURCE_RUNNING = 1 << 1,
- SYNCEVO_SOURCE_DONE = 1 << 2,
+ SYNCEVO_STATUS_UNKNOWN = 0,
+ SYNCEVO_STATUS_QUEUEING = 1 << 0,
+ SYNCEVO_STATUS_IDLE = 1 << 1,
+ SYNCEVO_STATUS_RUNNING = 1 << 2,
+ SYNCEVO_STATUS_ABORTING = 1 << 3,
+ SYNCEVO_STATUS_SUSPENDING = 1 << 4,
+ SYNCEVO_STATUS_DONE = 1 << 5,
/* the ones below are modifiers */
- SYNCEVO_SOURCE_WAITING = 1 << 3,
-} SyncevoSourceStatus;
+ SYNCEVO_STATUS_WAITING = 1 << 6
+} SyncevoSessionStatus;
+
typedef enum {
SYNCEVO_PHASE_NONE,
SYNCEVO_PHASE_RECEIVING,
} SyncevoSourcePhase;
-typedef struct {
- char *name;
- SyncevoSourcePhase phase;
- int prepare_current;
- int prepare_total;
- int send_current;
- int send_total;
- int receive_current;
- int receive_total;
-} SyncevoSourceProgress;
-
#define SYNCEVO_TYPE_SOURCE_STATUS (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INVALID))
#define SYNCEVO_TYPE_SOURCE_STATUSES (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, SYNCEVO_TYPE_SOURCE_STATUS))
#define SYNCEVO_TYPE_SOURCE_PROGRESS (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID))
typedef void (*SourceStatusFunc) (char *name,
SyncevoSyncMode mode,
- SyncevoSourceStatus status,
+ SyncevoSessionStatus status,
guint error_code,
gpointer user_data);
void
void syncevo_source_statuses_free (SyncevoSourceStatuses *source_statuses);
-
-SyncevoSourceProgress* syncevo_source_progresses_get_current (SyncevoSourceProgresses *source_progresses);
-
+typedef void (*SourceProgressFunc) (const char *name,
+ SyncevoSourcePhase phase,
+ gpointer user_data);
+void syncevo_source_progresses_foreach (SyncevoSourceProgresses *source_progresses,
+ SourceProgressFunc func,
+ gpointer userdata);
void syncevo_source_progresses_free (SyncevoSourceProgresses *source_progresses);
-void syncevo_source_progress_free (SyncevoSourceProgress *progress);
-
-
GHashTable* syncevo_reports_index (SyncevoReports *reports,
guint index);
guint syncevo_reports_get_length (SyncevoReports *reports);
SESSION_CHANGED,
PRESENCE_CHANGED,
INFO_REQUEST,
+ TEMPLATES_CHANGED,
SHUTDOWN,
LAST_SIGNAL
};
}
static void
+templates_changed_cb (DBusGProxy *proxy,
+ SyncevoServer *server)
+{
+ g_signal_emit (server, signals[TEMPLATES_CHANGED], 0);
+}
+
+static void
session_changed_cb (DBusGProxy *proxy,
char *session_path,
gboolean started,
char *state,
char *handler_path,
char *type,
+ GHashTable *parameters,
SyncevoServer *server)
{
g_signal_emit (server, signals[INFO_REQUEST], 0,
- id, session_path, state, handler_path, type);
+ id, session_path, state, handler_path, type, parameters);
}
static void
dbus_g_proxy_disconnect_signal (priv->proxy, "InfoRequest",
G_CALLBACK (info_request_cb),
object);
+ dbus_g_proxy_disconnect_signal (priv->proxy, "TemplatesChanged",
+ G_CALLBACK (templates_changed_cb),
+ object);
dbus_g_proxy_disconnect_signal (priv->proxy, "destroy",
G_CALLBACK (proxy_destroy_cb),
object);
G_TYPE_STRING,
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_STRING,
- DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_STRING,
+ G_TYPE_STRING,
+ DBUS_TYPE_G_STRING_STRING_HASHTABLE,
G_TYPE_INVALID);
dbus_g_proxy_connect_signal (priv->proxy, "InfoRequest",
G_CALLBACK (info_request_cb), server, NULL);
+ dbus_g_proxy_add_signal (priv->proxy, "TemplatesChanged", G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (priv->proxy, "TemplatesChanged",
+ G_CALLBACK (templates_changed_cb), server, NULL);
g_signal_connect (priv->proxy, "destroy",
G_CALLBACK (proxy_destroy_cb), server);
G_TYPE_STRING,
G_TYPE_INVALID);
/* InfoRequest */
- dbus_g_object_register_marshaller (syncevo_marshal_VOID__STRING_STRING_STRING_STRING_STRING,
+ dbus_g_object_register_marshaller (syncevo_marshal_VOID__STRING_STRING_STRING_STRING_STRING_BOXED,
G_TYPE_NONE,
G_TYPE_STRING,
DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_STRING,
- DBUS_TYPE_G_OBJECT_PATH,
G_TYPE_STRING,
+ G_TYPE_STRING,
+ DBUS_TYPE_G_STRING_STRING_HASHTABLE,
+ G_TYPE_INVALID);
+
+ /* TemplatesChanged */
+ dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
G_TYPE_INVALID);
syncevo_server_get_new_proxy (server);
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
G_STRUCT_OFFSET (SyncevoServerClass, info_request),
NULL, NULL,
- syncevo_marshal_VOID__STRING_STRING_STRING_STRING_STRING,
+ syncevo_marshal_VOID__STRING_STRING_STRING_STRING_STRING_BOXED,
G_TYPE_NONE,
- 5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ 6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, DBUS_TYPE_G_STRING_STRING_HASHTABLE);
+ signals[TEMPLATES_CHANGED] =
+ g_signal_new ("templates-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
+ G_STRUCT_OFFSET (SyncevoServerClass, templates_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
signals[SHUTDOWN] =
g_signal_new ("shutdown",
G_TYPE_FROM_CLASS (klass),
char *session_path,
char *state,
char *handler_path,
- char *type);
+ char *type,
+ GHashTable *parameters);
+
+ void (*templates_changed) (SyncevoServer *syncevo);
void (*shutdown) (SyncevoServer *syncevo);
} SyncevoServerClass;
data);
}
+void
+syncevo_session_restore (SyncevoSession *session,
+ const char *backup_dir,
+ const gboolean before,
+ const char **sources,
+ SyncevoSessionGenericCb callback,
+ gpointer userdata)
+{
+ SessionAsyncData *data;
+ SyncevoSessionPrivate *priv;
+
+ priv = GET_PRIVATE (session);
+
+ data = session_async_data_new (session, G_CALLBACK (callback), userdata);
+
+ if (!priv->proxy) {
+ if (callback) {
+ g_idle_add ((GSourceFunc)generic_error, data);
+ }
+ return;
+ }
+
+ org_syncevolution_Session_restore_async
+ (priv->proxy,
+ backup_dir,
+ before,
+ sources,
+ (org_syncevolution_Session_check_source_reply) generic_callback,
+ data);
+}
+
const char*
syncevo_session_get_path (SyncevoSession *session)
{
SyncevoSessionGenericCb callback,
gpointer userdata);
+void syncevo_session_restore (SyncevoSession *session,
+ const char *backup_dir,
+ const gboolean before,
+ const char **sources,
+ SyncevoSessionGenericCb callback,
+ gpointer userdata);
+
const char *syncevo_session_get_path (SyncevoSession *session);
SyncevoSession *syncevo_session_new (const char *path);
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
#include <boost/bind.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/variant.hpp>
+#include <boost/variant/get.hpp>
namespace boost {
void intrusive_ptr_add_ref(DBusConnection *con) { dbus_connection_ref(con); }
void intrusive_ptr_release(DBusConnection *con) { dbus_connection_unref(con); }
void intrusive_ptr_add_ref(DBusMessage *msg) { dbus_message_ref(msg); }
void intrusive_ptr_release(DBusMessage *msg) { dbus_message_unref(msg); }
+ void intrusive_ptr_add_ref(DBusPendingCall *call) {dbus_pending_call_ref (call); }
+ void intrusive_ptr_release(DBusPendingCall *call) {dbus_pending_call_unref (call); }
}
class DBusConnectionPtr : public boost::intrusive_ptr<DBusConnection>
}
};
+class DBusPendingCallPtr : public boost::intrusive_ptr<DBusPendingCall>
+{
+public:
+ DBusPendingCallPtr(DBusPendingCall *call, bool add_ref = false) :
+ boost::intrusive_ptr<DBusPendingCall>(call, add_ref)
+ {}
+
+ DBusPendingCall *reference(void) throw()
+ {
+ DBusPendingCall *call = get();
+ dbus_pending_call_ref(call);
+ return call;
+ }
+};
+
/**
* wrapper around DBusError which initializes
* the struct automatically, then can be used to
};
/**
+ * A boost::variant <V> maps to a dbus variant, only care about values of
+ * type V but will not throw error if type is not matched, this is useful if
+ * application is interested on only a sub set of possible value types
+ * in variant.
+ */
+template <class V> struct dbus_traits <boost::variant <V> > : public dbus_traits_base
+{
+ static std::string getType() { return "v"; }
+ static std::string getSignature() { return getType(); }
+ static std::string getReply() { return ""; }
+ static const int dbus = DBUS_TYPE_VARIANT;
+
+ static void get(DBusConnection *conn, DBusMessage *msg,
+ DBusMessageIter &iter, boost::variant <V> &value)
+ {
+ if (dbus_message_iter_get_arg_type(&iter) != dbus) {
+ throw std::runtime_error("invalid argument");
+ return;
+ }
+ DBusMessageIter sub;
+ dbus_message_iter_recurse(&iter, &sub);
+ if (dbus_message_iter_get_signature(&sub) != dbus_traits<V>::getSignature()){
+ //ignore unrecognized sub type in variant
+ return;
+ }
+ V val;
+ dbus_traits<V>::get (conn, msg, sub, val);
+ value = val;
+ }
+
+ static void append(DBusMessageIter &iter, const boost::variant <V> &value) {
+ }
+
+ //append_retval not implemented
+ //static void append_retval(DBusMessageIter &iter, arg_type array)
+ //{
+ //}
+
+ typedef boost::variant<V> host_type;
+ typedef const boost::variant<V> &arg_type;
+};
+
+/**
+ * A boost::variant <V1, V2> maps to a dbus variant, only care about values of
+ * type V1, V2 but will not throw error if type is not matched, this is useful if
+ * application is interested on only a sub set of possible value types
+ * in variant.
+ */
+template <class V1, class V2> struct dbus_traits <boost::variant <V1, V2> > : public dbus_traits_base
+{
+ static std::string getType() { return "v"; }
+ static std::string getSignature() { return getType(); }
+ static std::string getReply() { return ""; }
+ static const int dbus = DBUS_TYPE_VARIANT;
+
+ static void get(DBusConnection *conn, DBusMessage *msg,
+ DBusMessageIter &iter, boost::variant <V1, V2> &value)
+ {
+ if (dbus_message_iter_get_arg_type(&iter) != dbus) {
+ throw std::runtime_error("invalid argument");
+ return;
+ }
+ DBusMessageIter sub;
+ dbus_message_iter_recurse(&iter, &sub);
+ if (dbus_message_iter_get_signature(&sub) != dbus_traits<V1>::getSignature()
+ && dbus_message_iter_get_signature(&sub) != dbus_traits<V2>::getSignature()){
+ //ignore unrecognized sub type in variant
+ return;
+ } else if (dbus_message_iter_get_signature(&sub) == dbus_traits<V1>::getSignature()) {
+ V1 val;
+ dbus_traits<V1>::get (conn, msg, sub, val);
+ value = val;
+ } else {
+ V2 val;
+ dbus_traits<V2>::get (conn, msg, sub, val);
+ value = val;
+ }
+ }
+
+ static void append(DBusMessageIter &iter, const boost::variant <V1, V2> &value) {
+ }
+
+ typedef boost::variant<V1, V2> host_type;
+ typedef const boost::variant<V1, V2> &arg_type;
+};
+
+/**
* a single member m of type V in a struct K
*/
template<class K, class V, V K::*m> struct dbus_member_single
}
};
+/**
+ * interface to refer to a remote object
+ */
+class DBusRemoteObject : public DBusObject
+{
+public:
+ virtual const char *getDestination() const = 0;
+ virtual ~DBusRemoteObject() {}
+};
+/**
+ * interface expected by DBusClient
+ */
+class DBusCallObject : public DBusRemoteObject
+{
+public:
+ /* The method name for the calling dbus method */
+ virtual const char *getMethod() const =0;
+ virtual ~DBusCallObject() {}
+};
+
+/*
+ * A DBus Client Call object handling 0 argument and 1 return value.
+ */
+template <class R>
+class DBusClientCall0
+{
+ const std::string m_destination;
+ const std::string m_path;
+ const std::string m_interface;
+ const std::string m_method;
+ const DBusConnectionPtr m_conn;
+
+ /** called by libdbus on error or completion of call */
+ static void dbusCallback (DBusPendingCall *call, void *user_data)
+ {
+ DBusMessagePtr reply = dbus_pending_call_steal_reply (call);
+ const char* errname = dbus_message_get_error_name (reply.get());
+ std::string error;
+ typename dbus_traits<R>::host_type r;
+ if (!errname) {
+ DBusMessageIter iter;
+ dbus_message_iter_init(reply.get(), &iter);
+ //why need connection?
+ dbus_traits<R>::get(NULL, reply.get(), iter, r);
+ } else {
+ error = errname;
+ }
+ //unmarshal the return results and call user callback
+ (*static_cast <Callback_t *>(user_data))(r, error);
+ }
+
+ /**
+ * called by libdbus to free the user_data pointer set in
+ * dbus_pending_call_set_notify()
+ */
+ static void callDataUnref(void *user_data) {
+ delete static_cast <Callback_t *>(user_data);
+ }
+
+public:
+ /**
+ * called when result of call is available (R) or an error occurred (non-empty string)
+ */
+ typedef boost::function<void (const R &, const std::string &)> Callback_t;
+
+ DBusClientCall0 (const DBusCallObject &object)
+ :m_destination (object.getDestination()),
+ m_path (object.getPath()),
+ m_interface (object.getInterface()),
+ m_method (object.getMethod()),
+ m_conn (object.getConnection())
+ {
+ }
+
+ DBusClientCall0 (const DBusRemoteObject &object, const std::string &method)
+ :m_destination (object.getDestination()),
+ m_path (object.getPath()),
+ m_interface (object.getInterface()),
+ m_method (method),
+ m_conn (object.getConnection())
+ {
+ }
+
+ void operator () (const Callback_t &callback)
+ {
+ DBusPendingCall *call;
+ DBusMessagePtr msg(dbus_message_new_method_call(
+ m_destination.c_str(),
+ m_path.c_str(),
+ m_interface.c_str(),
+ m_method.c_str()));
+ if (!msg) {
+ throw std::runtime_error("dbus_message_new_method_call() failed");
+ }
+
+ //parameter marshaling (none)
+ if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
+ throw std::runtime_error("dbus_connection_send failed");
+ }
+
+ DBusPendingCallPtr mCall (call);
+ Callback_t *data = new Callback_t(callback);
+ dbus_pending_call_set_notify(mCall.get(),
+ dbusCallback,
+ data,
+ callDataUnref);
+ }
+};
+
+class SignalWatch
+{
+ protected:
+ const DBusRemoteObject &m_object;
+ std::string m_signal;
+
+ std::string makeSignalRule() {
+ std::string rule;
+ rule = "type='signal',path='";
+ rule += m_object.getPath();
+ rule += "',interface='";
+ rule += m_object.getInterface();
+ rule += "',member='";
+ rule += m_signal;
+ rule += "'";
+ return rule;
+ }
+
+ static gboolean isMatched(DBusMessage *msg, void *data) {
+ SignalWatch *watch = static_cast<SignalWatch*>(data);
+ return dbus_message_has_path(msg, watch->m_object.getPath()) &&
+ dbus_message_is_signal(msg, watch->m_object.getInterface(), watch->m_signal.c_str());
+ }
+
+ public:
+ SignalWatch(const DBusRemoteObject &object,
+ const std::string &signal)
+ : m_object(object), m_signal(signal)
+ {
+ }
+
+ virtual ~SignalWatch() {}
+};
+
+template <typename A1>
+class SignalWatch1 : public SignalWatch
+{
+ typedef boost::function<void (const A1 &)> Callback_t;
+ guint m_tag;
+ Callback_t *m_callback;
+
+ public:
+ SignalWatch1(const DBusRemoteObject &object,
+ const std::string &signal)
+ : SignalWatch(object, signal), m_tag(0), m_callback(0)
+ {
+ }
+
+ ~SignalWatch1()
+ {
+ if(m_tag) {
+ g_dbus_remove_watch(m_object.getConnection(), m_tag);
+ }
+ if(m_callback) {
+ delete m_callback;
+ }
+ }
+
+ static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
+ {
+ if(isMatched(msg, data) == FALSE) {
+ return TRUE;
+ }
+ SignalWatch1<A1> *watch = static_cast<SignalWatch1<A1>* >(data);
+
+ typename dbus_traits<A1>::host_type a1;
+
+ DBusMessageIter iter;
+ dbus_message_iter_init(msg, &iter);
+ dbus_traits<A1>::get(conn, msg, iter, a1);
+ (*watch->m_callback)(a1);
+
+ return TRUE;
+ }
+
+ void operator () (const Callback_t &callback)
+ {
+ m_callback = new Callback_t(callback);
+ std::string rule = makeSignalRule();
+ m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
+ rule.c_str(),
+ internalCallback,
+ this,
+ NULL);
+ }
+};
+
+template <typename A1, typename A2>
+class SignalWatch2 : public SignalWatch
+{
+ typedef boost::function<void (const A1 &, const A2 &)> Callback_t;
+
+ guint m_tag;
+ Callback_t *m_callback;
+ public:
+ SignalWatch2(const DBusRemoteObject &object,
+ const std::string &signal)
+ : SignalWatch(object, signal), m_tag(0), m_callback(0)
+ {
+ }
+
+ ~SignalWatch2()
+ {
+ if(m_tag) {
+ g_dbus_remove_watch(m_object.getConnection(), m_tag);
+ }
+ if(m_callback) {
+ delete m_callback;
+ }
+ }
+
+ static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
+ {
+ if(isMatched(msg, data) == FALSE) {
+ return TRUE;
+ }
+ SignalWatch2<A1, A2> *watch = static_cast<SignalWatch2<A1, A2> *>(data);
+
+ typename dbus_traits<A1>::host_type a1;
+ typename dbus_traits<A2>::host_type a2;
+
+ DBusMessageIter iter;
+ dbus_message_iter_init(msg, &iter);
+ dbus_traits<A1>::get(conn, msg, iter, a1);
+ dbus_traits<A2>::get(conn, msg, iter, a2);
+ (*watch->m_callback)(a1, a2);
+
+ return TRUE;
+ }
+
+ void operator () (const Callback_t &callback)
+ {
+ m_callback = new Callback_t(callback);
+ std::string rule = makeSignalRule();
+ m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
+ rule.c_str(),
+ internalCallback,
+ this,
+ NULL);
+ }
+};
+
#endif // INCL_GDBUS_CXX_BRIDGE
--- /dev/null
+plugindir = $(GNOMEBLUETOOTH_DIR)/plugins/
+
+INCLUDES = $(GNOMEBLUETOOTH_CFLAGS) \
+ -DLOCALEDIR=\"$(SYNCEVOLUTION_LOCALEDIR)\"
+
+plugin_LTLIBRARIES = libgbtsyncevolution.la
+libgbtsyncevolution_la_SOURCES = syncevolution.c
+libgbtsyncevolution_la_LDFLAGS = -module -avoid-version
+
--- /dev/null
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/gnome-bluetooth
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4-repo/ax_boost_base.m4 \
+ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(plugindir)"
+pluginLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+libgbtsyncevolution_la_LIBADD =
+am_libgbtsyncevolution_la_OBJECTS = syncevolution.lo
+libgbtsyncevolution_la_OBJECTS = $(am_libgbtsyncevolution_la_OBJECTS)
+libgbtsyncevolution_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgbtsyncevolution_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libgbtsyncevolution_la_SOURCES)
+DIST_SOURCES = $(libgbtsyncevolution_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADDRESSBOOK_CFLAGS = @ADDRESSBOOK_CFLAGS@
+ADDRESSBOOK_LIBS = @ADDRESSBOOK_LIBS@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BACKEND_CPPFLAGS = @BACKEND_CPPFLAGS@
+BACKEND_DEFINES = @BACKEND_DEFINES@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CORE_LDADD_DEP = @CORE_LDADD_DEP@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPUNIT_CXXFLAGS = @CPPUNIT_CXXFLAGS@
+CPPUNIT_LDFLAGS = @CPPUNIT_LDFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_BINDING_TOOL = @DBUS_BINDING_TOOL@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_CFLAGS = @DBUS_GLIB_CFLAGS@
+DBUS_GLIB_LIBS = @DBUS_GLIB_LIBS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SERVICES_DIR = @DBUS_SERVICES_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+EBOOK_CFLAGS = @EBOOK_CFLAGS@
+EBOOK_LIBS = @EBOOK_LIBS@
+ECAL_CFLAGS = @ECAL_CFLAGS@
+ECAL_LIBS = @ECAL_LIBS@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EPACKAGE_CFLAGS = @EPACKAGE_CFLAGS@
+EPACKAGE_LIBS = @EPACKAGE_LIBS@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FILE_CFLAGS = @FILE_CFLAGS@
+FILE_LIBS = @FILE_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+GTK_2_18_CFLAGS = @GTK_2_18_CFLAGS@
+GTK_2_18_LIBS = @GTK_2_18_LIBS@
+GTK_BUILDER_CONV = @GTK_BUILDER_CONV@
+GUI_CFLAGS = @GUI_CFLAGS@
+GUI_DESKTOP_FILES = @GUI_DESKTOP_FILES@
+GUI_LIBS = @GUI_LIBS@
+GUI_PROGRAMS = @GUI_PROGRAMS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+KEYRING_2_20_CFLAGS = @KEYRING_2_20_CFLAGS@
+KEYRING_2_20_LIBS = @KEYRING_2_20_LIBS@
+KEYRING_CFLAGS = @KEYRING_CFLAGS@
+KEYRING_LIBS = @KEYRING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
+LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MCALB_CFLAGS = @MCALB_CFLAGS@
+MCALB_LIBS = @MCALB_LIBS@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MODIFY_SYNCCOMPARE = @MODIFY_SYNCCOMPARE@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CFLAGS = @SQLITE_CFLAGS@
+SQLITE_LIBS = @SQLITE_LIBS@
+STABLE_VERSION = @STABLE_VERSION@
+STRIP = @STRIP@
+SYNCEVOLUTION_CXXFLAGS = @SYNCEVOLUTION_CXXFLAGS@
+SYNCEVOLUTION_LDADD = @SYNCEVOLUTION_LDADD@
+SYNCEVOLUTION_LOCALEDIR = @SYNCEVOLUTION_LOCALEDIR@
+SYNCSOURCES = @SYNCSOURCES@
+SYNTHESIS = @SYNTHESIS@
+SYNTHESISSRC = @SYNTHESISSRC@
+SYNTHESIS_CFLAGS = @SYNTHESIS_CFLAGS@
+SYNTHESIS_DEP = @SYNTHESIS_DEP@
+SYNTHESIS_ENGINE = @SYNTHESIS_ENGINE@
+SYNTHESIS_LIB = @SYNTHESIS_LIB@
+SYNTHESIS_LIBS = @SYNTHESIS_LIBS@
+SYNTHESIS_SRC = @SYNTHESIS_SRC@
+SYNTHESIS_SUBDIR = @SYNTHESIS_SUBDIR@
+TRANSPORT_CFLAGS = @TRANSPORT_CFLAGS@
+TRANSPORT_LIBS = @TRANSPORT_LIBS@
+UNIQUE_CFLAGS = @UNIQUE_CFLAGS@
+UNIQUE_LIBS = @UNIQUE_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XMLRPC_CFLAGS = @XMLRPC_CFLAGS@
+XMLRPC_LIBS = @XMLRPC_LIBS@
+XSLT = @XSLT@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+backenddir = @backenddir@
+backendsearchdir = @backendsearchdir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+plugindir = $(GNOMEBLUETOOTH_DIR)/plugins/
+INCLUDES = $(GNOMEBLUETOOTH_CFLAGS) \
+ -DLOCALEDIR=\"$(SYNCEVOLUTION_LOCALEDIR)\"
+
+plugin_LTLIBRARIES = libgbtsyncevolution.la
+libgbtsyncevolution_la_SOURCES = syncevolution.c
+libgbtsyncevolution_la_LDFLAGS = -module -avoid-version
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gnome-bluetooth/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/gnome-bluetooth/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(pluginLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(plugindir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$p"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgbtsyncevolution.la: $(libgbtsyncevolution_la_OBJECTS) $(libgbtsyncevolution_la_DEPENDENCIES)
+ $(libgbtsyncevolution_la_LINK) -rpath $(plugindir) $(libgbtsyncevolution_la_OBJECTS) $(libgbtsyncevolution_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syncevolution.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pluginLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pluginLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pluginLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-pluginLTLIBRARIES
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <bluetooth-plugin.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#define SYNCUI_BINARY "sync-ui"
+#define SYNCUI_ARG "--show-settings obex+bt://"
+
+/*Only detecting SyncML Client*/
+static gboolean
+has_config_widget (const char *bdaddr, const char **uuids)
+{
+ int i;
+ if (uuids == NULL) {
+ return FALSE;
+ }
+
+ for (i = 0; uuids[i] != NULL; i++) {
+ if (!g_strcmp0 (uuids[i], "SyncMLClient")) {
+ //find whether "sync-ui" is available
+ if (g_find_program_in_path (SYNCUI_BINARY) == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+button_clicked (GtkButton *button, gpointer user_data)
+{
+ const char *bdaddr;
+ pid_t midman;
+ pid_t syncui;
+ char args[sizeof (SYNCUI_ARG) + sizeof ("FF:FF:FF:FF:FF:FF") - 1];
+
+ bdaddr = g_object_get_data (G_OBJECT (button), "bdaddr");
+ midman = fork ();
+ if (midman == 0) {
+ //in midman process
+ syncui = fork();
+ if (syncui == 0) {
+ // in syncui process
+ strcpy (args, SYNCUI_ARG);
+ strncat (args, bdaddr, sizeof ("FF:FF:FF:FF:FF:FF"));
+ if (execlp (SYNCUI_BINARY, args, NULL) == -1){
+ g_warning ("SyncEvolution plugin failed to launch sync-ui!");
+ exit (-1);
+ }
+ } else if (syncui == -1) {
+ // error in forking sub process
+ g_warning ("SyncEvolution plugin failed to launch sync-ui!");
+ exit (-1);
+ } else {
+ //do nothing, just exit. This will cause sync-ui
+ //process an orphan.
+ exit (0);
+ }
+ } else if (midman == -1) {
+ //error in forking sub process
+ g_warning ("SyncEvolution plugin failed to launch sync-ui!");
+ } else {
+ //in bluetooth-panel process
+ if (waitpid (midman, NULL, 0) == -1){
+ //error in waitpid
+ g_warning ("SyncEvolution plugin failed to launch sync-ui!");
+ }
+ }
+}
+
+static GtkWidget *
+get_config_widgets (const char *bdaddr, const char **uuids)
+{
+ GtkWidget *hbox;
+ GtkWidget *button;
+ GtkWidget *label1;
+ GtkWidget *label2;
+ int label_max_width = 40;
+ int button_max_width = 10;
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ label1 = gtk_label_new (_("Sync in the Sync application"));
+ gtk_label_set_max_width_chars (GTK_LABEL(label1), label_max_width);
+ label2 = gtk_label_new (_("Sync"));
+ gtk_label_set_max_width_chars (GTK_LABEL(label2), button_max_width);
+ button = gtk_button_new ();
+ gtk_container_add (GTK_CONTAINER(button), label2);
+ g_object_set_data_full (G_OBJECT (button), "bdaddr", g_strdup (bdaddr), g_free);
+ gtk_widget_show (label1);
+ gtk_widget_show_all (button);
+ gtk_box_pack_start (GTK_BOX(hbox), label1, FALSE, FALSE, 6);
+ gtk_box_pack_end (GTK_BOX(hbox), button, FALSE, FALSE, 6);
+ /* And set the signal */
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (button_clicked), NULL);
+
+ return hbox;
+}
+
+static void
+device_removed (const char *bdaddr)
+{
+ //nothing todo
+}
+
+static GbtPluginInfo plugin_info = {
+ "SyncEvolution",
+ has_config_widget,
+ get_config_widgets,
+ device_removed
+};
+
+GBT_INIT_PLUGIN(plugin_info)
+
themerc_DATA = \
close.png close_hover.png settings.png settings_hover.png \
sync-generic.png \
+ sync-spinner.gif \
sync-ui.rc
desktopdir = $(datadir)/applications
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
themerc_DATA = \
close.png close_hover.png settings.png settings_hover.png \
sync-generic.png \
+ sync-spinner.gif \
sync-ui.rc
desktopdir = $(datadir)/applications
#include "config.h"
#include "sync-ui.h"
+static char *settings_id = NULL;
+
+static GOptionEntry entries[] =
+{
+ { "show-settings", 0, 0, G_OPTION_ARG_STRING, &settings_id, "Open sync settings for given sync url or configuration name", "url or config name" },
+ { NULL }
+};
+
+
static void
set_app_name_and_icon ()
{
gtk_window_set_default_icon_name ("sync");
}
+static void
+init (int argc, char *argv[])
+{
+ GError *error = NULL;
+ GOptionContext *context;
+
+ gtk_init (&argc, &argv);
+ bindtextdomain (GETTEXT_PACKAGE, SYNCEVOLUTION_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ context = g_option_context_new ("- synchronise PIM data with Syncevolution");
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_warning ("option parsing failed: %s\n", error->message);
+ }
+}
+
+
#ifdef ENABLE_UNIQUE
#include <unique/unique.h>
{
COMMAND_0,
+ COMMAND_SHOW_CONFIGURATION
/* no sync-ui specific commands */
};
UniqueCommand command,
UniqueMessageData *message,
guint time_,
- GtkWindow *main_win)
+ app_data *data)
{
- UniqueResponse res;
+ char *arg;
+ GtkWindow *main_win;
+ main_win = sync_ui_get_main_window (data);
switch (command) {
case UNIQUE_ACTIVATE:
if (GTK_IS_WINDOW (main_win)) {
unique_message_data_get_screen (message));
gtk_window_present (GTK_WINDOW (main_win));
}
- res = UNIQUE_RESPONSE_OK;
break;
- /* handle any sync-ui specific commands here */
+ case COMMAND_SHOW_CONFIGURATION:
+ arg = unique_message_data_get_text (message);
+ if (GTK_IS_WINDOW (main_win) && arg) {
+ /* move the main window to the screen that sent us the command */
+ gtk_window_set_screen (GTK_WINDOW (main_win),
+ unique_message_data_get_screen (message));
+ sync_ui_show_settings (data, arg);
+ }
+ break;
default:
- res = UNIQUE_RESPONSE_OK;
break;
}
- return res;
+ return UNIQUE_RESPONSE_OK;
}
int
{
UniqueApp *app;
- gtk_init (&argc, &argv);
- bindtextdomain (GETTEXT_PACKAGE, SYNCEVOLUTION_LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
+ init (argc, argv);
- app = unique_app_new ("org.Moblin.Sync", NULL);
+ app = unique_app_new_with_commands ("org.Moblin.Sync", NULL,
+ "show-configuration", COMMAND_SHOW_CONFIGURATION,
+ NULL);
if (unique_app_is_running (app)) {
+ UniqueMessageData *message = NULL;
+ UniqueCommand command = UNIQUE_ACTIVATE;
- unique_app_send_message (app, UNIQUE_ACTIVATE, NULL);
- /* could handle the response here... */
+ if (settings_id) {
+ command = COMMAND_SHOW_CONFIGURATION;
+ message = unique_message_data_new ();
+ unique_message_data_set_text (message, settings_id, -1);
+ }
+ unique_app_send_message (app, command, message);
+ unique_message_data_free (message);
} else {
- GtkWidget *main_win;
+ app_data *data;
set_app_name_and_icon ();
- main_win = sync_ui_create_main_window ();
- if (main_win) {
+ data = sync_ui_create ();
+ if (data) {
/* UniqueApp watches the main window so it can terminate
* the startup notification sequence for us */
- unique_app_watch_window (app, GTK_WINDOW (main_win));
+ unique_app_watch_window (app, sync_ui_get_main_window (data));
/* handle notifications from new app launches */
g_signal_connect (app, "message-received",
- G_CALLBACK (message_received_cb), main_win);
-
+ G_CALLBACK (message_received_cb), data);
+ if (settings_id) {
+ sync_ui_show_settings (data, settings_id);
+ }
gtk_main ();
}
}
int
main (int argc, char *argv[])
{
- gtk_init (&argc, &argv);
- bindtextdomain (GETTEXT_PACKAGE, SYNCEVOLUTION_LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
+ app_data *data;
+
+ init (argc, argv);
set_app_name_and_icon ();
+ data = sync_ui_create ();
+
+ if (settings_id) {
+ sync_ui_show_settings (data, settings_id);
+ }
- sync_ui_create_main_window ();
gtk_main ();
return 0;
}
enum {
PROP_0,
PROP_DECORATIONS,
+ PROP_BACK_TITLE,
};
enum {
case PROP_DECORATIONS:
g_value_set_uint (value, win->decorations);
break;
+ case PROP_BACK_TITLE:
+ g_value_set_string (value,
+ gtk_button_get_label (GTK_BUTTON (win->back_btn)));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
case PROP_DECORATIONS:
mux_window_set_decorations (win, g_value_get_uint (value));
break;
+ case PROP_BACK_TITLE:
+ g_free (win->back_title);
+ win->back_title = g_strdup (g_value_get_string (value));
+ if (win->back_btn) {
+ gtk_button_set_label (GTK_BUTTON (win->back_btn), win->back_title);
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
PROP_DECORATIONS,
pspec);
+ pspec = g_param_spec_string ("back-title",
+ NULL,
+ "title of the back button in the window decoration",
+ "",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_BACK_TITLE,
+ pspec);
+
mux_window_signals[SETTINGS_VISIBILITY_CHANGED] =
g_signal_new ("settings-visibility-changed",
G_OBJECT_CLASS_TYPE (object_class),
{
GtkWidget *box, *button_box, *btn, *align;
GdkPixbuf *pixbuf, *pixbuf_hover;
- gint index;
if (window->title_bar) {
gtk_widget_unparent (window->title_bar);
gtk_container_add (GTK_CONTAINER (align), button_box);
gtk_widget_show (button_box);
- btn = gtk_button_new_with_label (gtk_window_get_title (GTK_WINDOW (window)));
- gtk_box_pack_start (GTK_BOX (button_box), btn,
+ window->back_btn = gtk_button_new_with_label (window->back_title);
+ gtk_box_pack_start (GTK_BOX (button_box), window->back_btn,
FALSE, FALSE, 4);
- g_signal_connect (btn, "clicked",
+ g_signal_connect (window->back_btn, "clicked",
G_CALLBACK (bread_crumb_clicked_cb), window);
- gtk_widget_show (btn);
-
- index = mux_window_get_current_page (window);
- if (index > -1) {
- char *title;
- GtkWidget *page;
-
- page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (window->notebook), index);
- title = g_object_get_data (G_OBJECT (page), "title");
- if (title) {
- GtkWidget *img;
- img = gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD,
- GTK_ICON_SIZE_SMALL_TOOLBAR);
- gtk_box_pack_start (GTK_BOX (button_box), img,
- FALSE, FALSE, 4);
- gtk_widget_show (img);
-
- btn = gtk_button_new_with_label (title);
- gtk_box_pack_start (GTK_BOX (button_box), btn,
- FALSE, FALSE, 4);
- gtk_widget_show (btn);
- }
+ if (mux_window_get_current_page (window) != -1) {
+ gtk_widget_show (window->back_btn);
}
-
/*window->title_label = gtk_label_new (gtk_window_get_title (GTK_WINDOW (window)));
gtk_box_pack_start (GTK_BOX (box), window->title_label,
FALSE, FALSE, 0);
}
GtkWidget*
-mux_window_new (void)
+mux_window_new (const char *back_title)
{
- return g_object_new (MUX_TYPE_WINDOW, NULL);
+ return g_object_new (MUX_TYPE_WINDOW,
+ "back-title", back_title,
+ NULL);
}
void
gint
mux_window_append_page (MuxWindow *window,
- const char *title,
GtkWidget *page,
gboolean is_settings)
{
gint index;
index = gtk_notebook_append_page (GTK_NOTEBOOK (window->notebook), page, NULL);
- g_object_set_data_full (G_OBJECT (page), "title", g_strdup (title), g_free);
if (is_settings) {
window->settings_index = index;
if (bin->child) {
gtk_widget_show (bin->child);
}
+ gtk_widget_hide (window->back_btn);
} else {
gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), index);
if (bin->child) {
}
gtk_widget_show (window->notebook);
gtk_widget_map (window->notebook);
- }
- mux_window_build_title_bar (window);
+
+ gtk_widget_show (window->back_btn);
+ }
}
gint
GtkWindow parent;
GtkWidget *title_bar;
+ GtkWidget *back_btn;
GtkWidget *settings;
GtkWidget *settings_button;
GtkWidget *notebook;
MuxDecorations decorations;
GdkColor title_bar_color;
guint title_bar_height;
+ char *back_title;
+
} MuxWindow;
typedef struct {
GType mux_window_get_type (void);
-GtkWidget* mux_window_new (void);
+GtkWidget* mux_window_new (const char *back_title);
void mux_window_set_decorations (MuxWindow *window, MuxDecorations decorations);
MuxDecorations mux_window_get_decorations (MuxWindow *window);
void mux_window_set_settings_visible (MuxWindow *window, gboolean visible);
gboolean mux_window_get_settings_visible (MuxWindow *window);
-gint mux_window_append_page (MuxWindow *window, const char *title, GtkWidget *page, gboolean is_settings);
+gint mux_window_append_page (MuxWindow *window, GtkWidget *page, gboolean is_settings);
void mux_window_set_current_page (MuxWindow *window, gint index);
gint mux_window_get_current_page (MuxWindow *window);
GtkWidget *check;
GtkWidget *source_toggle_label;
+
+ guint count;
} source_widgets;
enum
PROP_SERVER,
PROP_NAME,
+ PROP_CONFIG,
PROP_CURRENT,
PROP_HAS_TEMPLATE,
PROP_CONFIGURED,
widgets = (source_widgets*)g_hash_table_lookup (self->sources, name);
if (!widgets) {
- g_warning ("No widgets found for source %s", name);
return;
}
return;
}
+ self->configured = TRUE;
+
g_object_unref (session);
g_signal_emit (self, signals[SIGNAL_CHANGED], 0);
}
gboolean delete)
{
if (delete) {
- syncevo_config_free (self->config->config);
- self->config->config = g_hash_table_new (g_str_hash, g_str_equal);
+ syncevo_config_free (self->config);
+ self->config = g_hash_table_new (g_str_hash, g_str_equal);
}
-
syncevo_session_set_config (session,
FALSE,
FALSE,
- self->config->config,
+ self->config,
(SyncevoSessionGenericCb)set_config_cb,
self);
}
stop_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
save_config_data *data;
- SyncevoConfig *config;
if (!self->config) {
return;
}
- config = self->config->config;
-
- syncevo_config_set_value (config, NULL, "defaultPeer", "");
+ syncevo_config_set_value (self->config, NULL, "defaultPeer", "");
sync_config_widget_set_current (self, FALSE);
data = g_slice_new (save_config_data);
data->widget = self;
data->delete = FALSE;
syncevo_server_start_session (self->server,
- self->config->name,
+ self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
}
static void
use_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
- SyncevoConfig *config;
save_config_data *data;
- const char *username, *password, *sync_url;
- char *real_url;
+ const char *username, *password, *sync_url, *pretty_name;
+ char *real_url, *device;
gboolean send, receive;
SyncevoSyncMode mode;
}
if (self->current_service_name && !self->current) {
- GtkWidget *w, *top_level;
- int ret;
- char *msg, *yes, *no;
+ gboolean ret;
+ char *msg, *yes, *no, *new_name, *old_name;
/*TRANSLATORS: warning dialog text for changing current service */
msg = g_strdup_printf
- (_("Do you want to replace %s with %s? This\n"
- "will not remove any synced information on either\n"
- "end but you will no longer be able to sync with\n"
- "%s."),
+ (_("Do you want to replace %s with %s? This "
+ "will not remove any synced information on either "
+ "end but you will no longer be able to sync with %s."),
self->current_service_name,
gtk_entry_get_text (GTK_ENTRY (self->entry)),
self->current_service_name);
+
+ new_name = g_strndup (gtk_entry_get_text (GTK_ENTRY (self->entry)), 40);
+ old_name = g_strndup (self->current_service_name, 40);
+
/* TRANSLATORS: decline/accept buttons in warning dialog.
Placeholder is service name */
- yes = g_strdup_printf (_("Yes, use %s"),
- gtk_entry_get_text (GTK_ENTRY (self->entry)));
- no = g_strdup_printf (_("No, use %s"), self->current_service_name);
- top_level = gtk_widget_get_toplevel (GTK_WIDGET (self));
- w = gtk_message_dialog_new (GTK_WINDOW (top_level),
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_NONE,
- msg);
- gtk_dialog_add_buttons (GTK_DIALOG (w),
- no, GTK_RESPONSE_NO,
- yes, GTK_RESPONSE_YES,
- NULL);
- ret = gtk_dialog_run (GTK_DIALOG (w));
- gtk_widget_destroy (w);
+ yes = g_strdup_printf (_("Yes, use %s"), new_name);
+ no = g_strdup_printf (_("No, use %s"), old_name);
+
+ ret = show_confirmation (GTK_WIDGET (self), msg, yes, no);
+
g_free (msg);
g_free (yes);
g_free (no);
+ g_free (new_name);
+ g_free (old_name);
- if (ret != GTK_RESPONSE_YES) {
+ if (!ret) {
return;
}
}
- config = self->config->config;
- self->config->name = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry)));
+ if (strlen (self->config_name) == 0) {
+ g_free (self->config_name);
+ self->config_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->entry)));
+ }
if (self->mode_changed) {
GHashTableIter iter;
source_widgets *widgets;
char *name;
- g_object_get (self->send_check, "active", &send, NULL);
- g_object_get (self->receive_check, "active", &receive, NULL);
+ send = toggle_get_active (self->send_check);
+ receive = toggle_get_active (self->receive_check);
if (send && receive) {
mode = SYNCEVO_SYNC_TWO_WAY;
const char *mode_str;
gboolean active;
- g_object_get (widgets->check, "active", &active, NULL);
+ active = toggle_get_active (widgets->check);
if (active) {
mode_str = syncevo_sync_mode_to_string (mode);
} else {
mode_str = "none";
}
- syncevo_config_set_value (config, name, "sync", mode_str);
+ syncevo_config_set_value (self->config, name, "sync", mode_str);
}
}
username = gtk_entry_get_text (GTK_ENTRY (self->username_entry));
- syncevo_config_set_value (config, NULL, "username", username);
+ syncevo_config_set_value (self->config, NULL, "username", username);
sync_url = gtk_entry_get_text (GTK_ENTRY (self->baseurl_entry));
/* make a wild guess if no scheme in url */
} else {
real_url = g_strdup (sync_url);
}
- syncevo_config_set_value (config, NULL, "syncURL", real_url);
+ syncevo_config_set_value (self->config, NULL, "syncURL", real_url);
password = gtk_entry_get_text (GTK_ENTRY (self->password_entry));
- syncevo_config_set_value (config, NULL, "password", password);
-
-
- if (!self->config->name || strlen (self->config->name) == 0 ||
- !sync_url || strlen (sync_url) == 0) {
- /* TODO show in UI: service settings missing name or url */
- show_error_dialog (GTK_WIDGET (self),
- _("Service must have a name and server URL"));
- return;
+ syncevo_config_set_value (self->config, NULL, "password", password);
+
+ syncevo_config_get_value (self->config, NULL, "deviceName", &device);
+ if (!device || strlen (device) == 0) {
+ if (!self->config_name || strlen (self->config_name) == 0 ||
+ !sync_url || strlen (sync_url) == 0) {
+ show_error_dialog (GTK_WIDGET (self),
+ _("Service must have a name and server URL"));
+ return;
+ }
}
- syncevo_config_foreach_source (config,
+ syncevo_config_foreach_source (self->config,
(ConfigFunc)update_source_uri,
self);
- syncevo_config_set_value (config, NULL, "defaultPeer", self->config->name);
+ pretty_name = gtk_entry_get_text (GTK_ENTRY (self->entry));
+ syncevo_config_set_value (self->config, NULL, "PeerName", pretty_name);
+ syncevo_config_get_value (self->config, NULL, "PeerName", &self->pretty_name);
+ syncevo_config_set_value (self->config, NULL, "defaultPeer", self->config_name);
sync_config_widget_set_current (self, TRUE);
data = g_slice_new (save_config_data);
data->widget = self;
data->delete = FALSE;
syncevo_server_start_session (self->server,
- self->config->name,
+ self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
static void
reset_delete_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
{
- GtkWidget *w, *top_level;
- int ret;
- char *msg, *yes;
+ char *msg, *yes, *no;
save_config_data *data;
if (!self->config) {
/*TRANSLATORS: warning dialog text for resetting pre-defined
services */
msg = g_strdup_printf
- (_("Do you want to reset the settings for %s?\n"
+ (_("Do you want to reset the settings for %s? "
"This will not remove any synced information on either end."),
- self->config->name);
- /*TRANSLATORS: accept button in warning dialog */
+ self->pretty_name);
+ /*TRANSLATORS: buttons in reset-service warning dialog */
yes = _("Yes, reset");
+ no = _("No, keep settings");
} else {
/*TRANSLATORS: warning dialog text for deleting user-defined
services */
msg = g_strdup_printf
- (_("Do you want to delete the settings for %s?\n"
- "This will not remove any synced information on either\n"
+ (_("Do you want to delete the settings for %s? "
+ "This will not remove any synced information on either "
"end but it will remove this service configuration."),
- self->config->name);
- /*TRANSLATORS: accept button in warning dialog */
+ self->pretty_name);
+ /*TRANSLATORS: buttons in delete-service warning dialog */
yes = _("Yes, delete");
+ no = _("No, keep settings");
}
- top_level = gtk_widget_get_toplevel (GTK_WIDGET (self));
- w = gtk_message_dialog_new (GTK_WINDOW (top_level),
- GTK_DIALOG_MODAL,
- GTK_MESSAGE_QUESTION,
- GTK_BUTTONS_NONE,
- msg);
- /*TRANSLATORS: decline button in warning dialog */
- gtk_dialog_add_buttons (GTK_DIALOG (w),
- _("No, keep settings"),
- GTK_RESPONSE_NO,
- yes,
- GTK_RESPONSE_YES,
- NULL);
- ret = gtk_dialog_run (GTK_DIALOG (w));
- gtk_widget_destroy (w);
- g_free (msg);
-
- if (ret != GTK_RESPONSE_YES) {
+ /*TRANSLATORS: decline button in "Reset/delete service" warning dialogs */
+ if (!show_confirmation (GTK_WIDGET (self), msg, yes, no)) {
+ g_free (msg);
return;
}
+ g_free (msg);
if (self->current) {
sync_config_widget_set_current (self, FALSE);
data->widget = self;
data->delete = TRUE;
syncevo_server_start_session (self->server,
- self->config->name,
+ self->config_name,
(SyncevoServerStartSessionCb)start_session_for_config_write_cb,
data);
}
}
}
+static void
+source_widgets_ref (source_widgets *widgets)
+{
+ if (widgets) {
+ widgets->count++;
+ }
+}
+
+static void
+source_widgets_unref (source_widgets *widgets)
+{
+ if (widgets) {
+ widgets->count--;
+ if (widgets->count == 0)
+ g_slice_free (source_widgets, widgets);
+ }
+}
static void
check_source_cb (SyncevoServer *server,
source_widgets *widgets)
{
gboolean show = TRUE;
+
if (error) {
if(error->code == DBUS_GERROR_REMOTE_EXCEPTION &&
dbus_g_error_has_name (error, SYNCEVO_DBUS_ERROR_SOURCE_UNUSABLE)) {
-
show = FALSE;
} else if (error->code == DBUS_GERROR_REMOTE_EXCEPTION &&
dbus_g_error_has_name (error,
g_error_free (error);
}
- if (show) {
+ if (show && widgets->count > 1) {
+ /* TODO: with the new two sources per row layout not showing things
+ * probably won't look good... */
gtk_widget_show (widgets->source_toggle_label);
gtk_widget_show (widgets->label);
gtk_widget_show (widgets->entry);
gtk_widget_show (widgets->check);
}
+ source_widgets_unref (widgets);
}
static void
old_editable = GTK_WIDGET_SENSITIVE (widgets->check);
if (new_editable != old_editable) {
gtk_widget_set_sensitive (widgets->check, new_editable);
- g_object_set (widgets->check, "active", new_editable, NULL);
+ toggle_set_active (widgets->check, new_editable);
}
}
col = col * 2;
label = gtk_label_new (title);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_widget_set_size_request (label, 260, -1);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- gtk_widget_show (label);
gtk_table_attach (GTK_TABLE (self->mode_table), label,
col, col + 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
toggle = mx_gtk_light_switch_new ();
+ g_signal_connect_swapped (toggle, "hide",
+ G_CALLBACK (gtk_widget_hide), label);
+ g_signal_connect_swapped (toggle, "show",
+ G_CALLBACK (gtk_widget_show), label);
+ toggle_set_active (toggle, active);
+ g_signal_connect (toggle, "switch-flipped",
+ G_CALLBACK (mode_widget_notify_active_cb), self);
#else
toggle = gtk_check_button_new_with_label (title);
+ gtk_widget_set_size_request (toggle, 260, -1);
+ toggle_set_active (toggle, active);
+ g_signal_connect (toggle, "notify::active",
+ G_CALLBACK (mode_widget_notify_active_cb), self);
#endif
- g_object_set (toggle, "active", active, NULL);
- gtk_widget_show (toggle);
gtk_table_attach (GTK_TABLE (self->mode_table), toggle,
col + 1, col + 2, row, row + 1,
GTK_FILL, GTK_FILL, 32, 0);
- g_signal_connect (toggle, "notify::active",
- G_CALLBACK (mode_widget_notify_active_cb), self);
return toggle;
}
+
+/* check if config includes a virtual source that covers the given
+ * source */
+static gboolean
+virtual_source_exists (SyncevoConfig *config, const char *name)
+{
+ GHashTableIter iter;
+ const char *source_string;
+ GHashTable *source_config;
+
+ g_hash_table_iter_init (&iter, config);
+ while (g_hash_table_iter_next (&iter,
+ (gpointer)&source_string,
+ (gpointer)&source_config)) {
+ char **strs;
+
+ if (g_str_has_prefix (source_string, "source/")) {
+ const char *uri, *type;
+ type = g_hash_table_lookup (source_config, "type");
+ uri = g_hash_table_lookup (source_config, "uri");
+
+ if (!uri || !type || !g_str_has_prefix (type, "virtual:")) {
+ /* this source is not defined, or not virtual */
+ continue;
+ }
+
+ strs = g_strsplit (source_string + 7, "+", 0);
+ if (g_strv_length (strs) > 1) {
+ int i;
+
+ for (i = 0; strs[i]; i++) {
+ if (g_strcmp0 (name, strs[i]) == 0) {
+ g_strfreev (strs);
+ return TRUE;
+ }
+ }
+ }
+ g_strfreev (strs);
+ }
+ }
+
+ return FALSE;
+}
+
static void
init_source (char *name,
GHashTable *source_configuration,
SyncConfigWidget *self)
{
char *str, *pretty_name;
- const char *uri;
+ const char *uri, *type;
guint rows;
guint row;
static guint col = 0;
source_widgets *widgets;
SyncevoSyncMode mode;
+ type = g_hash_table_lookup (source_configuration, "type");
+ uri = g_hash_table_lookup (source_configuration, "uri");
+ if (!type || strlen (type) == 0) {
+ return;
+ }
+
+ if (g_str_has_prefix (type, "virtual:") && !uri) {
+ /* undefined virtual source */
+ return;
+ }
+
+ if (virtual_source_exists (self->config, name)) {
+ return;
+ }
+
g_object_get (self->mode_table,
"n-rows", &rows,
NULL);
}
self->no_source_toggles = FALSE;
- widgets = g_slice_new (source_widgets);
+ widgets = g_slice_new0 (source_widgets);
+ widgets->count = 1;
g_hash_table_insert (self->sources, name, widgets);
widgets->source_toggle_label = self->source_toggle_label;
- uri = g_hash_table_lookup (source_configuration, "uri");
pretty_name = get_pretty_source_name (name);
mode = syncevo_sync_mode_from_string
(g_hash_table_lookup (source_configuration, "sync"));
gtk_widget_set_sensitive (widgets->check,
uri && strlen (uri) > 0);
+ /* TODO: template sources cannot be checked. Should set a temporary config
+ * to check sources */
if (self->configured) {
+ source_widgets_ref (widgets);
syncevo_server_check_source (self->server,
- self->config->name,
+ self->config_name,
name,
(SyncevoServerGenericCb)check_source_cb,
widgets);
} else {
- /* TODO: should do a temp config to test eve n template sources */
gtk_widget_show (widgets->source_toggle_label);
gtk_widget_show (widgets->label);
gtk_widget_show (widgets->entry);
SyncevoSyncMode *common_mode)
{
SyncevoSyncMode mode;
- char *mode_str;
+ char *mode_str, *type;
+
+ type = g_hash_table_lookup (source_configuration, "type");
+ if (!type || strlen (type) == 0) {
+ return;
+ }
mode_str = g_hash_table_lookup (source_configuration, "sync");
mode = syncevo_sync_mode_from_string (mode_str);
}
}
-static void
-source_widgets_free (source_widgets *widgets)
+void
+sync_config_widget_expand_id (SyncConfigWidget *self,
+ const char *id)
{
- if (widgets) {
- g_slice_free (source_widgets, widgets);
+ if (id && self->config) {
+ char *sync_url;
+
+ if (syncevo_config_get_value (self->config, NULL,
+ "syncURL", &sync_url) &&
+ strncmp (sync_url, id, strlen (id)) == 0) {
+
+ sync_config_widget_set_expanded (self, TRUE);
+ } else if (self->config_name &&
+ g_strcasecmp (self->config_name, id) == 0) {
+
+ sync_config_widget_set_expanded (self, TRUE);
+ }
}
}
-
static void
sync_config_widget_update_expander (SyncConfigWidget *self)
{
char *password = "";
char *sync_url = "";
const char *descr;
- char *str;
+ char *str, *device;
GtkWidget *label, *align;
SyncevoSyncMode mode = SYNCEVO_SYNC_NONE;
gboolean send, receive;
- SyncevoConfig *config = self->config->config;
gtk_container_foreach (GTK_CONTAINER (self->server_settings_table),
(GtkCallback)remove_child,
gtk_table_resize (GTK_TABLE (self->mode_table),
2, 1);
- /* TODO: sources that are not supported locally will trigger the complex
- * config warning for no real reason... should do get_common_mode only after
- * check_source calls, and make sure unsupported sources do not get edited */
- syncevo_config_foreach_source (config,
+ syncevo_config_get_value (self->config, NULL, "PeerIsClient", &device);
+ if (device && g_strcmp0 (device, "1") == 0) {
+ if (!self->device_template_selected) {
+ gtk_widget_hide (self->settings_box);
+ gtk_widget_show (self->device_selector_box);
+ /* temporary solution for device template selection:
+ * show list of templates only */
+ } else {
+ gtk_widget_show (self->settings_box);
+ gtk_widget_hide (self->device_selector_box);
+ gtk_widget_hide (self->userinfo_table);
+ gtk_widget_hide (self->fake_expander);
+ }
+ } else {
+ gtk_widget_show (self->settings_box);
+ gtk_widget_hide (self->device_selector_box);
+ gtk_widget_show (self->userinfo_table);
+ gtk_widget_show (self->fake_expander);
+ }
+
+ syncevo_config_foreach_source (self->config,
(ConfigFunc)get_common_mode,
&mode);
switch (mode) {
break;
default:
gtk_widget_show (self->complex_config_info_bar);
- g_warning ("sync mode config is more complex than UI can handle");
send = FALSE;
receive = FALSE;
}
self->mode_changed = FALSE;
- if (self->config->name) {
- gtk_entry_set_text (GTK_ENTRY (self->entry), self->config->name);
+ if (self->pretty_name) {
+ gtk_entry_set_text (GTK_ENTRY (self->entry), self->pretty_name);
}
- if (!self->config->name || strlen (self->config->name) == 0) {
+ if (!self->config_name || strlen (self->config_name) == 0) {
gtk_expander_set_expanded (GTK_EXPANDER (self->expander), TRUE);
}
- descr = get_service_description (self->config->name);
+ descr = get_service_description (self->config_name);
if (descr) {
gtk_label_set_text (GTK_LABEL (self->description_label),
- get_service_description (self->config->name));
+ get_service_description (self->config_name));
gtk_widget_show (self->description_label);
} else {
gtk_widget_hide (self->description_label);
update_buttons (self);
- /* TRANSLATORS: check button (or toggle) in service configuration form */
- str = g_strdup_printf (_("Send changes to %s"), self->config->name);
+ /* TRANSLATORS: toggles in service configuration form, placeholder is service
+ * or device name */
+ str = g_strdup_printf (_("Send changes to %s"), self->pretty_name);
self->send_check = add_toggle_widget (self, str, send, 0, 0);
g_free (str);
- /* TRANSLATORS: check button (or toggle) in service configuration form */
- str = g_strdup_printf (_("Receive changes from %s"), self->config->name);
+ str = g_strdup_printf (_("Receive changes from %s"), self->pretty_name);
self->receive_check = add_toggle_widget (self, str, receive, 0, 1);
g_free (str);
gtk_widget_show (self->source_toggle_label);
gtk_container_add (GTK_CONTAINER (align), self->source_toggle_label);
- syncevo_config_get_value (config, NULL, "username", &username);
- syncevo_config_get_value (config, NULL, "password", &password);
- syncevo_config_get_value (config, NULL, "syncURL", &sync_url);
+ syncevo_config_get_value (self->config, NULL, "username", &username);
+ syncevo_config_get_value (self->config, NULL, "password", &password);
+ syncevo_config_get_value (self->config, NULL, "syncURL", &sync_url);
if (username) {
gtk_entry_set_text (GTK_ENTRY (self->username_entry), username);
self->sources = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
- (GDestroyNotify)source_widgets_free);
+ (GDestroyNotify)source_widgets_unref);
self->no_source_toggles = TRUE;
- syncevo_config_foreach_source (config,
+ syncevo_config_foreach_source (self->config,
(ConfigFunc)init_source,
self);
}
+/* only adds config to hashtable and combo */
+static void
+sync_config_widget_add_config (SyncConfigWidget *self,
+ const char *name,
+ SyncevoConfig *config)
+{
+ g_hash_table_insert (self->configs, g_strdup (name), config);
+ gtk_combo_box_prepend_text (GTK_COMBO_BOX (self->combo), name);
+}
+
+static void
+sync_config_widget_update_pretty_name (SyncConfigWidget *self)
+{
+ self->pretty_name = NULL;
+
+ if (self->config) {
+ syncevo_config_get_value (self->config, NULL,
+ "PeerName", &self->pretty_name);
+ if (!self->pretty_name) {
+ syncevo_config_get_value (self->config, NULL,
+ "deviceName", &self->pretty_name);
+ }
+ }
+
+ if (!self->pretty_name) {
+ self->pretty_name = self->config_name;
+ }
+}
+
+static void
+sync_config_widget_set_config (SyncConfigWidget *self,
+ SyncevoConfig *config)
+{
+ self->config = config;
+ sync_config_widget_update_pretty_name (self);
+}
+
+
static void
setup_service_clicked (GtkButton *btn, SyncConfigWidget *self)
{
}
static void
+sync_config_widget_set_name (SyncConfigWidget *self,
+ const char *name)
+{
+ g_free (self->config_name);
+ self->config_name = g_strdup (name);
+ sync_config_widget_update_pretty_name (self);
+}
+
+
+static void
+device_selection_btn_clicked_cb (GtkButton *btn, SyncConfigWidget *self)
+{
+ const char *name;
+ SyncevoConfig *config;
+
+ self->device_template_selected = TRUE;
+
+ name = gtk_combo_box_get_active_text (GTK_COMBO_BOX (self->combo));
+ config = g_hash_table_lookup (self->configs, name);
+
+ g_return_if_fail (config);
+
+ sync_config_widget_set_config (self, config);
+ sync_config_widget_set_name (self, name);
+
+ sync_config_widget_update_expander (self);
+}
+
+static void
server_settings_notify_expand_cb (GtkExpander *expander,
GParamSpec *pspec,
SyncConfigWidget *self)
static void
sync_config_widget_update_label (SyncConfigWidget *self)
{
- if (self->config && self->config->name && self->config->config) {
- char *url;
+ if (self->config && self->pretty_name) {
+ char *url, *sync_url;
char *str;
- syncevo_config_get_value (self->config->config, NULL, "WebURL", &url);
+ syncevo_config_get_value (self->config, NULL, "WebURL", &url);
+ syncevo_config_get_value (self->config, NULL, "syncURL", &sync_url);
if (self->current) {
- str = g_strdup_printf ("<b>%s</b>", self->config->name);
+ str = g_strdup_printf ("<b>%s</b>", self->pretty_name);
} else {
- str = g_strdup_printf ("%s", self->config->name);
+ str = g_strdup_printf ("%s", self->pretty_name);
}
- if (!self->has_template) {
+ if (g_str_has_prefix (sync_url, "obex-bt://")) {
+ char *tmp = g_strdup_printf (_("%s - Bluetooth device"), str);
+ g_free (str);
+ str = tmp;
+ } else if (!self->has_template) {
/* TRANSLATORS: service title for services that are not based on a
* template in service list, the placeholder is the name of the service */
char *tmp = g_strdup_printf (_("%s - manually setup"), str);
if (started) {
set_session (self, path);
- } else if (self->running_session &&
- strcmp (self->running_session, path) == 0 ) {
+ } else if (g_strcmp0 (self->running_session, path) == 0 ) {
set_session (self, NULL);
}
}
}
static void
-sync_config_widget_set_name (SyncConfigWidget *self,
- const char *name)
-{
- self->config = g_slice_new0 (server_config);
- self->config->name = g_strdup (name);
-}
-
-static void
sync_config_widget_set_property (GObject *object,
guint property_id,
const GValue *value,
case PROP_NAME:
sync_config_widget_set_name (self, g_value_get_string (value));
break;
+ case PROP_CONFIG:
+ sync_config_widget_set_config (self, g_value_get_pointer (value));
+ break;
case PROP_CURRENT:
sync_config_widget_set_current (self, g_value_get_boolean (value));
break;
case PROP_SERVER:
g_value_set_pointer (value, self->server);
case PROP_NAME:
- if (self->config)
- g_value_set_string (value, self->config->name);
- else
- g_value_set_string (value, NULL);
+ g_value_set_string (value, self->config_name);
+ case PROP_CONFIG:
+ g_value_set_pointer (value, self->config);
case PROP_CURRENT:
g_value_set_boolean (value, self->current);
case PROP_HAS_TEMPLATE:
case PROP_CURRENT_SERVICE_NAME:
g_value_set_string (value, self->current_service_name);
case PROP_EXPANDED:
- g_value_set_boolean (value, self->expanded);
+ g_value_set_boolean (value, self->expanded);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
SyncConfigWidget *self = SYNC_CONFIG_WIDGET (object);
sync_config_widget_set_server (self, NULL);
-
- G_OBJECT_CLASS (sync_config_widget_parent_class)->dispose (object);
-}
-
-static void
-init_default_config (server_config *config)
-{
- g_free (config->name);
- config->name = g_strdup ("");
-
- syncevo_config_set_value (config->config, NULL, "username", "");
- syncevo_config_set_value (config->config, NULL, "password", "");
- syncevo_config_set_value (config->config, NULL, "syncURL", "");
- syncevo_config_set_value (config->config, NULL, "WebURL", "");
- syncevo_config_set_value (config->config, "memo", "uri", "");
- syncevo_config_set_value (config->config, "todo", "uri", "");
- syncevo_config_set_value (config->config, "addressbook", "uri", "");
- syncevo_config_set_value (config->config, "calendar", "uri", "");
-
-}
-
-static void
-sync_config_widget_real_init (SyncConfigWidget *self,
- SyncevoConfig *config)
-{
- char *url, *icon;
- GdkPixbuf *buf;
- server_config_init (self->config, config);
- if (self->config->name &&
- strcmp (self->config->name, "default") == 0) {
-
- init_default_config (self->config);
- self->has_template = FALSE;
- gtk_widget_show (self->entry);
- gtk_widget_hide (self->label);
- } else {
- /**/
- gtk_widget_hide (self->entry);
- gtk_widget_show (self->label);
+ if (self->config) {
+ syncevo_config_free (self->config);
}
+ self->config = NULL;
- syncevo_config_get_value (self->config->config, NULL, "WebURL", &url);
- syncevo_config_get_value (self->config->config, NULL, "IconURI", &icon);
-
- buf = load_icon (icon, SYNC_UI_LIST_ICON_SIZE);
- gtk_image_set_from_pixbuf (GTK_IMAGE (self->image), buf);
- g_object_unref (buf);
-
- if (url && strlen (url) > 0) {
- gtk_link_button_set_uri (GTK_LINK_BUTTON (self->link), url);
- gtk_widget_show (self->link);
- } else {
- gtk_widget_hide (self->link);
+ if (self->configs) {
+ g_hash_table_destroy (self->configs);
+ self->configs = NULL;
+ }
+ g_free (self->config_name);
+ self->config_name = NULL;
+ g_free (self->current_service_name);
+ self->current_service_name = NULL;
+ g_free (self->running_session);
+ self->running_session = NULL;
+ if (self->sources) {
+ g_hash_table_destroy (self->sources);
+ self->sources = NULL;
}
- sync_config_widget_update_label (self);
- sync_config_widget_update_expander (self);
- if (self->showing) {
- gtk_widget_show (GTK_WIDGET (self));
- /* hack to get focus in the right place on "Setup new service" */
- if (GTK_WIDGET_VISIBLE (self->entry)) {
- gtk_widget_grab_focus (self->entry);
- }
- }
+ G_OBJECT_CLASS (sync_config_widget_parent_class)->dispose (object);
}
static void
-get_config_cb (SyncevoServer *syncevo,
- SyncevoConfig *config,
- GError *error,
- SyncConfigWidget *self)
+init_default_config (SyncConfigWidget *self)
{
- if (error) {
- g_warning ("Server.GetConfig failed: %s", error->message);
- g_error_free (error);
- g_object_thaw_notify (G_OBJECT (self));
+ sync_config_widget_set_name (self, "");
+ self->has_template = FALSE;
- /* TODO: show in UI */
- return;
- }
- sync_config_widget_real_init (self, config);
- g_object_thaw_notify (G_OBJECT (self));
+ syncevo_config_set_value (self->config, NULL, "username", "");
+ syncevo_config_set_value (self->config, NULL, "password", "");
+ syncevo_config_set_value (self->config, NULL, "syncURL", "");
+ syncevo_config_set_value (self->config, NULL, "WebURL", "");
+ syncevo_config_set_value (self->config, "memo", "uri", "");
+ syncevo_config_set_value (self->config, "todo", "uri", "");
+ syncevo_config_set_value (self->config, "addressbook", "uri", "");
+ syncevo_config_set_value (self->config, "calendar", "uri", "");
}
rect.width,
rect.height);
- if (self->expanded) {
- gint shadow_x, shadow_y;
-
- shadow_x = rect.x + widget->style->xthickness;
- shadow_y = rect.y + 2 * widget->style->ythickness +
- self->label_box->allocation.height;
-
- gtk_paint_box (widget->style,
- widget->window,
- widget->state,
- GTK_SHADOW_IN,
- &rect,
- widget,
- NULL,
- shadow_x,
- shadow_y,
- rect.width - (shadow_x - rect.x) - widget->style->xthickness,
- rect.height - (shadow_y - rect.y) - widget->style->ythickness);
- }
-
-
gtk_container_propagate_expose (GTK_CONTAINER (self),
self->label_box, event);
gtk_container_propagate_expose (GTK_CONTAINER (self),
{
SyncConfigWidget *self;
GObjectClass *parent_class;
+ char *url, *icon;
+ GdkPixbuf *buf;
parent_class = G_OBJECT_CLASS (sync_config_widget_parent_class);
self = SYNC_CONFIG_WIDGET (parent_class->constructor (gtype,
n_properties,
properties));
- if (!self->server) {
- g_warning ("No SyncevoServer set for SyncConfigWidget");
+ if (!self->config || !self->server) {
+ g_warning ("No SyncevoServer or Syncevoconfig set for SyncConfigWidget");
+ return G_OBJECT (self);
}
- /* freeze notifys so we don't claim to have expanded until we have...
- this could be achieved in more clean ways as well... */
- g_object_freeze_notify (G_OBJECT (self));
- syncevo_server_get_config (self->server,
- self->config->name,
- self->has_template && !self->configured,
- (SyncevoServerGetConfigCb)get_config_cb,
- self);
- return G_OBJECT (self);
-}
+ sync_config_widget_add_config (self, self->config_name, self->config);
-static void
-sync_config_widget_show (GtkWidget *widget)
-{
- char *ready;
- SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
+ if (g_strcmp0 (self->config_name, "default") == 0) {
- /* this is a bit dirty... might be better to show the widget
- * in any case and handle removing non-ready templates otherwise */
- self->showing = TRUE;
- if (self->config && self->config->config) {
- syncevo_config_get_value (self->config->config,
- NULL, "ConsumerReady", &ready);
+ init_default_config (self);
+ gtk_widget_show (self->entry);
+ gtk_widget_hide (self->label);
+ } else {
+ gtk_widget_hide (self->entry);
+ gtk_widget_show (self->label);
+ }
- if (self->configured || g_strcmp0 ("1", ready) == 0) {
- GTK_WIDGET_CLASS (sync_config_widget_parent_class)->show (widget);
- }
+ syncevo_config_get_value (self->config, NULL, "WebURL", &url);
+ syncevo_config_get_value (self->config, NULL, "IconURI", &icon);
+
+ buf = load_icon (icon, SYNC_UI_LIST_ICON_SIZE);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (self->image), buf);
+ g_object_unref (buf);
+
+ if (url && strlen (url) > 0) {
+ gtk_link_button_set_uri (GTK_LINK_BUTTON (self->link), url);
+ gtk_widget_show (self->link);
+ } else {
+ gtk_widget_hide (self->link);
}
-}
-static void
-sync_config_widget_hide (GtkWidget *widget)
-{
- SyncConfigWidget *self = SYNC_CONFIG_WIDGET (widget);
+ sync_config_widget_update_label (self);
+ sync_config_widget_update_expander (self);
+
+ /* hack to get focus in the right place on "Setup new service" */
+ if (GTK_WIDGET_VISIBLE (self->entry)) {
+ gtk_widget_grab_focus (self->entry);
+ }
- self->showing = FALSE;
- GTK_WIDGET_CLASS (sync_config_widget_parent_class)->hide (widget);
+ return G_OBJECT (self);
}
static void
}
static void
-sync_config_widget_realize (GtkWidget *widget)
-{
- GTK_WIDGET_CLASS (sync_config_widget_parent_class)->realize (widget);
-}
-
-static void
-sync_config_widget_unrealize (GtkWidget *widget)
-{
- GTK_WIDGET_CLASS (sync_config_widget_parent_class)->unrealize (widget);
-}
-
-static void
sync_config_widget_add (GtkContainer *container,
GtkWidget *widget)
{
object_class->dispose = sync_config_widget_dispose;
object_class->constructor = sync_config_widget_constructor;
- w_class->show = sync_config_widget_show;
- w_class->hide = sync_config_widget_hide;
w_class->expose_event = sync_config_widget_expose_event;
w_class->size_request = sync_config_widget_size_request;
w_class->size_allocate = sync_config_widget_size_allocate;
w_class->map = sync_config_widget_map;
w_class->unmap = sync_config_widget_unmap;
- w_class->realize = sync_config_widget_realize;
- w_class->unrealize = sync_config_widget_unrealize;
c_class->add = sync_config_widget_add;
c_class->remove = sync_config_widget_remove;
pspec = g_param_spec_pointer ("server",
"SyncevoServer",
- "The SyncevoServer struct this widget represents",
+ "The SyncevoServer to use in Syncevolution DBus calls",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_SERVER, pspec);
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_NAME, pspec);
+ pspec = g_param_spec_pointer ("config",
+ "SyncevoConfig",
+ "The SyncevoConfig struct this widget represents. Takes ownership.",
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_CONFIG, pspec);
+
pspec = g_param_spec_boolean ("current",
"Current",
"Whether the service is currently used",
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_EXPANDED, pspec);
- pspec = g_param_spec_int ("expander-size",
- "Expander Size",
- "Size of the expander indicator",
- 0, G_MAXINT, INDICATOR_SIZE,
- G_PARAM_READABLE);
-
- gtk_widget_class_install_style_property (w_class, pspec);
-
-
signals[SIGNAL_CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
static void
sync_config_widget_init (SyncConfigWidget *self)
{
- GtkWidget *tmp_box, *hbox, *cont, *vbox, *table, *label;
+ GtkWidget *tmp_box, *hbox, *cont, *vbox, *label, *btn;
GTK_WIDGET_SET_FLAGS (GTK_WIDGET (self), GTK_NO_WINDOW);
+ /* should free the config? */
+ self->configs = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
self->label_box = gtk_event_box_new ();
gtk_widget_set_app_paintable (self->label_box, TRUE);
gtk_widget_show (self->label_box);
gtk_box_pack_start (GTK_BOX (hbox), tmp_box, FALSE, FALSE, 8);
self->label = gtk_label_new ("");
+ gtk_label_set_max_width_chars (GTK_LABEL (self->label), 60);
+ gtk_label_set_ellipsize (GTK_LABEL (self->label), PANGO_ELLIPSIZE_END);
gtk_misc_set_alignment (GTK_MISC (self->label), 0.0, 0.5);
gtk_widget_show (self->label);
gtk_box_pack_start (GTK_BOX (tmp_box), self->label, FALSE, FALSE, 0);
gtk_widget_set_no_show_all (self->expando_box, TRUE);
gtk_widget_set_parent (self->expando_box, GTK_WIDGET (self));
+ /* device_selector_box does device template selection */
+ self->device_selector_box = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (self->expando_box), self->device_selector_box,
+ TRUE, TRUE, 16);
+
+ hbox = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (self->device_selector_box), hbox,
+ FALSE, TRUE, 16);
+ self->combo = gtk_combo_box_new_text ();
+ gtk_widget_set_size_request (self->combo, 200, -1);
+ gtk_widget_show (self->combo);
+ gtk_box_pack_start (GTK_BOX (hbox), self->combo,
+ FALSE, TRUE, 0);
+ btn = gtk_button_new_with_label ("Use these settings");
+ gtk_widget_show (btn);
+ gtk_box_pack_start (GTK_BOX (hbox), btn,
+ FALSE, TRUE, 0);
+ g_signal_connect (btn, "clicked",
+ G_CALLBACK (device_selection_btn_clicked_cb), self);
+
+ /* settings_box has normal expander contents */
+ self->settings_box = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (self->settings_box);
+ gtk_box_pack_start (GTK_BOX (self->expando_box), self->settings_box,
+ TRUE, TRUE, 16);
+
vbox = gtk_vbox_new (FALSE, 8);
gtk_widget_show (vbox);
- gtk_box_pack_start (GTK_BOX (self->expando_box), vbox, TRUE, TRUE, 16);
+ gtk_box_pack_start (GTK_BOX (self->settings_box), vbox, TRUE, TRUE, 0);
tmp_box = gtk_vbox_new (FALSE, 0);
gtk_widget_show (tmp_box);
gtk_widget_show (tmp_box);
gtk_box_pack_start (GTK_BOX (vbox), tmp_box, FALSE, FALSE, 0);
- table = gtk_table_new (4, 2, FALSE);
- gtk_table_set_row_spacings (GTK_TABLE (table), 2);
- gtk_table_set_col_spacings (GTK_TABLE (table), 5);
- gtk_widget_show (table);
- gtk_box_pack_start (GTK_BOX (tmp_box), table, FALSE, FALSE, 0);
+ self->userinfo_table = gtk_table_new (4, 2, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (self->userinfo_table), 2);
+ gtk_table_set_col_spacings (GTK_TABLE (self->userinfo_table), 5);
+ gtk_widget_show (self->userinfo_table);
+ gtk_box_pack_start (GTK_BOX (tmp_box), self->userinfo_table, FALSE, FALSE, 0);
/* TRANSLATORS: labels of entries in service configuration form */
label = gtk_label_new (_("Username"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
- gtk_table_attach_defaults (GTK_TABLE (table), label,
+ gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), label,
0, 1,
0, 1);
gtk_widget_show (self->username_entry);
gtk_entry_set_width_chars (GTK_ENTRY (self->username_entry), 40);
gtk_entry_set_max_length (GTK_ENTRY (self->username_entry), 99);
- gtk_table_attach_defaults (GTK_TABLE (table), self->username_entry,
+ gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), self->username_entry,
1, 2,
0, 1);
label = gtk_label_new (_("Password"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_widget_show (label);
- gtk_table_attach_defaults (GTK_TABLE (table), label,
+ gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), label,
0, 1,
1, 2);
gtk_entry_set_width_chars (GTK_ENTRY (self->password_entry), 40);
gtk_entry_set_visibility (GTK_ENTRY (self->password_entry), FALSE);
gtk_entry_set_max_length (GTK_ENTRY (self->password_entry), 99);
- gtk_table_attach_defaults (GTK_TABLE (table), self->password_entry,
+ gtk_table_attach_defaults (GTK_TABLE (self->userinfo_table), self->password_entry,
1, 2,
1, 2);
GtkWidget*
sync_config_widget_new (SyncevoServer *server,
const char *name,
+ SyncevoConfig *config,
gboolean current,
const char *current_service_name,
gboolean configured,
return g_object_new (SYNC_TYPE_CONFIG_WIDGET,
"server", server,
"name", name,
+ "config", config,
"current", current,
"current-service-name", current_service_name,
"configured", configured,
{
if (self->configured != configured) {
self->configured = configured;
+ self->device_template_selected = configured;
update_buttons (self);
}
}
const char*
sync_config_widget_get_name (SyncConfigWidget *widget)
{
- if (!widget->config)
- return NULL;
+ return widget->config_name;
+}
- return widget->config->name;
+void
+sync_config_widget_add_alternative_config (SyncConfigWidget *self,
+ const char *name,
+ SyncevoConfig *config,
+ gboolean configured)
+{
+ if (configured) {
+ sync_config_widget_set_config (self, config);
+ sync_config_widget_set_configured (self, TRUE);
+ } else {
+ sync_config_widget_add_config (self, name, config);
+ }
+ sync_config_widget_update_expander (self);
}
#include <gtk/gtk.h>
#include "syncevo-server.h"
-#include "sync-ui-config.h"
G_BEGIN_DECLS
GtkWidget *expando_box;
GtkWidget *label_box;
+ GtkWidget *device_selector_box;
+ GtkWidget *combo;
+
+ GtkWidget *settings_box;
+
gboolean current; /* is this currently used config */
char *current_service_name; /* name of the current service */
gboolean configured; /* actual service configuration exists on server */
+ gboolean device_template_selected;
gboolean has_template; /* this service configuration has a matching template */
- gboolean showing;
gboolean expanded;
SyncevoServer *server;
- server_config *config;
-
+ SyncevoConfig *config;
+ GHashTable *configs; /* possible configs. config above is one of these */
+
+ char *config_name;
+ char *pretty_name;
+
char *running_session;
+ char *expand_id;
+
/* label */
GtkWidget *image;
GtkWidget *label;
/* content */
GtkWidget *description_label;
+ GtkWidget *userinfo_table;
GtkWidget *name_label;
GtkWidget *name_entry;
GtkWidget *complex_config_info_bar;
GtkWidget *sync_config_widget_new (SyncevoServer *server,
const char *name,
+ SyncevoConfig *config,
gboolean current,
const char *current_service_name,
gboolean configured,
gboolean sync_config_widget_get_configured (SyncConfigWidget *self);
const char *sync_config_widget_get_name (SyncConfigWidget *widget);
+
+void sync_config_widget_expand_id (SyncConfigWidget *self, const char *id);
+void sync_config_widget_add_alternative_config (SyncConfigWidget *self, const char *name, SyncevoConfig *config, gboolean configured);
G_END_DECLS
syncevo_config_foreach_source (config,
(ConfigFunc)add_source_config,
server->source_configs);
-
+ if (!syncevo_config_get_value (config, NULL, "PeerName", &server->pretty_name)) {
+ server->pretty_name = server->name;
+ }
}
+gboolean
+source_config_is_usable (source_config *source)
+{
+ const char *source_uri;
+
+ source_uri = g_hash_table_lookup (source->config, "uri");
+
+ if (!source_config_is_enabled (source) ||
+ !source_uri ||
+ strlen (source_uri) == 0 ||
+ !source->supported_locally) {
+ return FALSE;
+ }
+ return TRUE;
+}
gboolean
source_config_is_enabled (source_config *source)
char *mode;
mode = g_hash_table_lookup (source->config, "sync");
-
if (mode &&
(strcmp (mode, "none") == 0 ||
strcmp (mode, "disabled") == 0)) {
#include "syncevo-session.h"
#include "syncevo-server.h"
-/* need a separate struct for sources because we need to know local support ... */
typedef struct source_config {
char *name;
gboolean supported_locally;
+ SyncevoSourcePhase phase;
+
gboolean stats_set;
long status;
long local_changes;
typedef struct server_config {
char *name;
+ char *pretty_name;
char *password;
/* any field in config has changed */
gboolean changed;
SyncevoConfig *config;
} server_config;
+gboolean source_config_is_usable (source_config *source);
gboolean source_config_is_enabled (source_config *source);
void source_config_free (source_config *source);
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
#include "syncevo-server.h"
#include "syncevo-session.h"
#endif
static gboolean support_canceling = FALSE;
+#define REPORTS_PER_CALL 10
#define SYNC_UI_ICON_SIZE 48
#define STRING_VARIANT_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
+typedef enum bluetooth_type {
+ SYNC_BLUETOOTH_NONE,
+ SYNC_BLUETOOTH_GNOME,
+ SYNC_BLUETOOTH_MOBLIN
+} bluetooth_type;
+
typedef enum app_state {
SYNC_UI_STATE_CURRENT_STATE,
SYNC_UI_STATE_GETTING_SERVER,
SYNC_UI_STATE_SYNCING,
} app_state;
-typedef struct app_data {
+typedef enum ui_operation {
+ OP_SYNC, /* use sync mode from config */
+ OP_SYNC_SLOW,
+ OP_SYNC_REFRESH_FROM_CLIENT,
+ OP_SYNC_REFRESH_FROM_SERVER,
+ OP_SAVE,
+ OP_RESTORE,
+} ui_operation;
+
+typedef struct operation_data {
+ app_data *data;
+ ui_operation operation;
+ gboolean started;
+ const char *dir; /* for OP_RESTORE */
+} operation_data;
+
+struct _app_data {
GtkWidget *sync_win;
GtkWidget *services_win; /* will be NULL when USE_MOBLIN_UX is set*/
GtkWidget *offline_label;
GtkWidget *progress;
GtkWidget *sync_status_label;
+ GtkWidget *spinner_image;
GtkWidget *sync_btn;
GtkWidget *change_service_btn;
GtkWidget *emergency_btn;
GtkWidget *sources_box;
GtkWidget *new_service_btn;
+ GtkWidget *new_device_btn;
GtkWidget *services_box;
+ GtkWidget *devices_box;
GtkWidget *scrolled_window;
GtkWidget *back_btn;
GtkWidget *expanded_config;
GtkWidget *emergency_label;
GtkWidget *emergency_expander;
GtkWidget *emergency_source_table;
- GtkWidget *emergency_from_client_btn;
- GtkWidget *emergency_from_server_btn;
+ GtkWidget *refresh_from_server_btn_label;
+ GtkWidget *refresh_from_client_btn_label;
+ GtkWidget *emergency_backup_table;
+
+ GtkWidget *password_dialog_entry;
+ char *password_dialog_id;
gboolean forced_emergency;
GHashTable *emergency_sources;
+ guint backup_count;
gboolean online;
int last_sync;
guint last_sync_src_id;
+ ui_operation current_operation;
server_config *current_service;
app_state current_state;
gboolean open_current; /* should the service list open the current
service when it populates next time*/
+ char *config_id_to_open;
SyncevoServer *server;
SyncevoSession *running_session; /* session that is currently active */
-} app_data;
-typedef struct operation_data {
- app_data *data;
- enum op {
- OP_SYNC, /* use sync mode from config */
- OP_SYNC_SLOW,
- OP_SYNC_REFRESH_FROM_CLIENT,
- OP_SYNC_REFRESH_FROM_SERVER,
- OP_SAVE,
- } operation;
- gboolean started;
-} operation_data;
+ bluetooth_type bluetooth_wizard;
+};
static void set_sync_progress (app_data *data, float progress, char *status);
static void set_app_state (app_data *data, app_state state);
static void show_main_view (app_data *data);
static void update_emergency_view (app_data *data);
+static void update_emergency_expander (app_data *data);
static void show_emergency_view (app_data *data);
-static void show_services_list (app_data *data);
+static void show_services_list (app_data *data, const char *config_id_to_open);
static void update_services_list (app_data *data);
static void update_service_ui (app_data *data);
static void setup_new_service_clicked (GtkButton *btn, app_data *data);
static void get_config_for_main_win_cb (SyncevoServer *server, SyncevoConfig *config,
GError *error, app_data *data);
+
+void
+toggle_set_active (GtkWidget *toggle, gboolean active)
+{
+#ifdef USE_MOBLIN_UX
+ /* MxGtkLightSwitch does not have "active" property yet */
+ mx_gtk_light_switch_set_active (MX_GTK_LIGHT_SWITCH (toggle), active);
+#else
+ g_object_set (toggle, "active", active, NULL);
+#endif
+}
+
+gboolean
+toggle_get_active (GtkWidget *toggle)
+{
+#ifdef USE_MOBLIN_UX
+ /* MxGtkLightSwitch does not have "active" property yet */
+ return mx_gtk_light_switch_get_active (MX_GTK_LIGHT_SWITCH (toggle));
+#else
+ gboolean active;
+ g_object_get (toggle, "active", &active, NULL);
+ return active;
+#endif
+}
+
void
show_error_dialog (GtkWidget *widget, const char* message)
{
change_service_clicked_cb (GtkButton *btn, app_data *data)
{
/* data->open_current = TRUE; */
- show_services_list (data);
+ show_services_list (data, NULL);
}
static void
} else if (strcmp (source_name, "todo") == 0) {
return g_strdup (_("Tasks"));
} else if (strcmp (source_name, "memo") == 0) {
- return g_strdup (_("Memo"));
+ return g_strdup (_("Notes"));
} else if (strcmp (source_name, "calendar+todo") == 0) {
/* TRANSLATORS: This is a "combination source" for syncing with devices
* that combine appointments and tasks. the name should match the ones
}
}
-/*
-static void
-add_error_info (app_data *data, const char *message, const char *external_reason)
+char*
+get_pretty_source_name_markup (const char *source_name)
{
- GtkWidget *lbl;
- GList *l, *children;
-
- children = gtk_container_get_children (GTK_CONTAINER (data->service_error_box));
- for (l = children; l; l = l->next) {
- GtkLabel *old_lbl = GTK_LABEL (l->data);
-
- if (strcmp (message, gtk_label_get_text (old_lbl)) == 0) {
- g_list_free (children);
- return;
- }
- }
- g_list_free (children);
+ char *plain, *markup;
- gtk_widget_show (data->errors_box);
-
- lbl = gtk_label_new (message);
- gtk_label_set_line_wrap (GTK_LABEL (lbl), TRUE);
-
- gtk_widget_set_size_request (lbl, 160, -1);
- gtk_widget_show (lbl);
- gtk_misc_set_alignment (GTK_MISC (lbl), 0.0, 0.5);
- gtk_box_pack_start (GTK_BOX (data->service_error_box), lbl, FALSE, FALSE, 0);
-
- if (external_reason) {
- g_warning ("%s: %s", message, external_reason);
- } else {
- g_warning ("%s", message);
- }
+ plain = get_pretty_source_name (source_name);
+ markup = g_markup_escape_text (plain, -1);
+ g_free (plain);
+ return markup;
}
-*/
static void
reload_config (app_data *data, const char *server)
set_app_state (data, SYNC_UI_STATE_SYNCING);
}
-static gboolean
-confirm (app_data *data, const char *message, const char *yes)
+gboolean
+show_confirmation (GtkWidget *widget, const char *message,
+ const char *yes, const char *no)
{
GtkWidget *w;
int ret;
- w = gtk_message_dialog_new (GTK_WINDOW (data->sync_win),
+ w = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (widget)),
GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_NONE,
"%s",
message);
gtk_dialog_add_buttons (GTK_DIALOG (w),
- _("No, cancel sync"),
- GTK_RESPONSE_NO,
- yes,
- GTK_RESPONSE_YES,
+ no, GTK_RESPONSE_NO,
+ yes, GTK_RESPONSE_YES,
NULL);
ret = gtk_dialog_run (GTK_DIALOG (w));
gtk_widget_destroy (w);
return (ret == GTK_RESPONSE_YES);
}
+
static void
-slow_sync_clicked_cb (GtkButton *btn, app_data *data)
+slow_sync (app_data *data)
{
operation_data *op_data;
char *message;
+ /* TRANSLATORS: slow sync confirmation dialog message. Placeholder
+ * is service/device name */
message = g_strdup_printf (_("Do you want to slow sync with %s?"),
- data->current_service->name);
- if (!confirm (data, message, _("Yes, do slow sync"))) {
+ data->current_service->pretty_name);
+ /* TRANSLATORS: slow sync confirmation dialog buttons */
+ if (!show_confirmation (data->sync_win, message,
+ _("Yes, do slow sync"), _("No, cancel sync"))) {
g_free (message);
return;
}
show_main_view (data);
}
+static void
+slow_sync_clicked_cb (GtkButton *btn, app_data *data)
+{
+ slow_sync (data);
+}
+
static void
refresh_from_server_clicked_cb (GtkButton *btn, app_data *data)
operation_data *op_data;
char *message;
+ /* TRANSLATORS: confirmation dialog for refresh-from-server. Placeholder
+ * is service/device name */
message = g_strdup_printf (_("Do you want to delete all local data and replace it with "
"data from %s? This is not usually advised."),
- data->current_service->name);
- if (!confirm (data, message, _("Yes, delete and replace"))) {
+ data->current_service->pretty_name);
+ /* TRANSLATORS: refresh-from-server confirmation dialog buttons */
+ if (!show_confirmation (data->sync_win, message,
+ _("Yes, delete and replace"), _("No"))) {
g_free (message);
return;
}
operation_data *op_data;
char *message;
+ /* TRANSLATORS: confirmation dialog for refresh-from-client. Placeholder
+ * is service/device name */
message = g_strdup_printf (_("Do you want to delete all data in %s and replace it with "
"your local data? This is not usually advised."),
- data->current_service->name);
- if (!confirm (data, message, _("Yes, delete and replace"))) {
+ data->current_service->pretty_name);
+ /* TRANSLATORS: refresh-from-client confirmation dialog buttons */
+ if (!show_confirmation (data->sync_win, message,
+ _("Yes, delete and replace"), _("No"))) {
g_free (message);
return;
}
}
static void
-sync_clicked_cb (GtkButton *btn, app_data *data)
+start_sync (app_data *data)
{
operation_data *op_data;
}
}
+
+static void
+sync_clicked_cb (GtkButton *btn, app_data *data)
+{
+ start_sync (data);
+}
+
static gboolean
refresh_last_synced_label (app_data *data)
{
msg = g_strdup (_("No service selected"));
delay = -1;
} else if (data->last_sync <= 0) {
- msg = g_strdup (data->current_service->name); /* we don't know */
+ msg = g_strdup (data->current_service->pretty_name); /* we don't know */
delay = -1;
} else if (diff < 30) {
/* TRANSLATORS: This is the title on main view. Placeholder is
* the service name. Example: "Google - synced just now" */
msg = g_strdup_printf (_("%s - synced just now"),
- data->current_service->name);
+ data->current_service->pretty_name);
delay = 30;
} else if (diff < 90) {
msg = g_strdup_printf (_("%s - synced a minute ago"),
- data->current_service->name);
+ data->current_service->pretty_name);
delay = 60;
} else if (diff < 60 * 60) {
msg = g_strdup_printf (_("%s - synced %ld minutes ago"),
- data->current_service->name,
+ data->current_service->pretty_name,
(diff + 30) / 60);
delay = 60;
} else if (diff < 60 * 90) {
msg = g_strdup_printf (_("%s - synced an hour ago"),
- data->current_service->name);
+ data->current_service->pretty_name);
delay = 60 * 60;
} else if (diff < 60 * 60 * 24) {
msg = g_strdup_printf (_("%s - synced %ld hours ago"),
- data->current_service->name,
+ data->current_service->pretty_name,
(diff + 60 * 30) / (60 * 60));
delay = 60 * 60;
} else if (diff < 60 * 60 * 24 - (60 * 30)) {
msg = g_strdup_printf (_("%s - synced a day ago"),
- data->current_service->name);
+ data->current_service->pretty_name);
delay = 60 * 60 * 24;
} else {
msg = g_strdup_printf (_("%s - synced %ld days ago"),
- data->current_service->name,
+ data->current_service->pretty_name,
(diff + 24 * 60 * 30) / (60 * 60 * 24));
delay = 60 * 60 * 24;
}
(GtkCallback)remove_child,
container);
switch (response_id) {
+ case SYNC_ERROR_RESPONSE_SYNC:
+ /* TRANSLATORS: Action button in info bar in main view. Shown with e.g.
+ * "You've just restored a backup. The changes have not been "
+ * "synced with %s yet" */
+ gtk_info_bar_add_button (bar, _("Sync now"), response_id);
+ break;
case SYNC_ERROR_RESPONSE_EMERGENCY:
- /* TRANSLATORS: Buttons in error/info bars. */
- gtk_info_bar_add_button (bar, _("Fix it"), response_id);
+ /* TRANSLATORS: Action button in info bar in main view. Shown with e.g.
+ * "A normal sync is not possible at this time..." message.
+ * "Other options" will open Emergency view */
+ gtk_info_bar_add_button (bar, _("Slow sync"), SYNC_ERROR_RESPONSE_EMERGENCY_SLOW_SYNC);
+ gtk_info_bar_add_button (bar, _("Other options..."), response_id);
break;
case SYNC_ERROR_RESPONSE_SETTINGS_SELECT:
+ /* TRANSLATORS: Action button in info bar in main view. Shown e.g.
+ * when no service is selected. Will open configuration view */
gtk_info_bar_add_button (bar, _("Select sync service"), response_id);
break;
case SYNC_ERROR_RESPONSE_SETTINGS_OPEN:
+ /* TRANSLATORS: Action button in info bar in main view. Shown e.g.
+ * login to service fails. Will open configuration view for this service */
gtk_info_bar_add_button (bar, _("Edit service settings"), response_id);
break;
case SYNC_ERROR_RESPONSE_NONE:
gtk_widget_set_sensitive (data->emergency_btn, TRUE);
/* TRANSLATORS: These are for the button in main view, right side.
Keep line length below ~20 characters, use two lines if needed */
- if (data->synced_this_session)
+ if (data->synced_this_session && data->current_operation != OP_RESTORE)
gtk_button_set_label (GTK_BUTTON (data->sync_btn), _("Sync again"));
else
gtk_button_set_label (GTK_BUTTON (data->sync_btn), _("Sync now"));
/* we have a active session, and a session is running
(the running session may or may not be ours) */
gtk_widget_show (data->progress);
- gtk_label_set_text (GTK_LABEL (data->sync_status_label), _("Syncing"));
+ if (data->current_operation == OP_RESTORE) {
+ gtk_label_set_text (GTK_LABEL (data->sync_status_label), _("Restoring"));
+ } else {
+ gtk_label_set_text (GTK_LABEL (data->sync_status_label), _("Syncing"));
+ }
gtk_widget_set_sensitive (data->main_frame, FALSE);
gtk_widget_set_sensitive (data->change_service_btn, FALSE);
gtk_widget_set_sensitive (data->emergency_btn, FALSE);
- gtk_widget_set_sensitive (data->sync_btn, support_canceling);
- if (support_canceling) {
+ gtk_widget_set_sensitive (data->sync_btn,
+ support_canceling && data->current_operation != OP_RESTORE);
+ if (support_canceling && support_canceling && data->current_operation != OP_RESTORE) {
/* TRANSLATORS: This is for the button in main view, right side.
Keep line length below ~20 characters, use two lines if needed */
gtk_button_set_label (GTK_BUTTON (data->sync_btn), _("Cancel sync"));
}
#ifdef USE_MOBLIN_UX
-static void
-settings_visibility_changed_cb (GtkWidget *window, app_data *data)
-{
- if (mux_window_get_settings_visible (MUX_WINDOW (window))) {
- update_services_list (data);
- }
-}
/* truly stupid, but glade doesn't allow custom containers.
Now glade file has dummy containers that will be replaced here.
}
static void
+settings_visibility_changed_cb (MuxWindow *win, app_data *data)
+{
+ update_services_list (data);
+}
+
+static void
setup_windows (app_data *data,
GtkWidget *main,
GtkWidget *settings,
g_assert (GTK_IS_WINDOW (settings));
g_assert (GTK_IS_WINDOW (emergency));
- mux_main = mux_window_new ();
+ /* TRANSLATORS: button in the Moblin window title bar when main view is
+ * not visible */
+ mux_main = mux_window_new (_("Back to sync"));
gtk_window_set_title (GTK_WINDOW (mux_main),
gtk_window_get_title (GTK_WINDOW (main)));
gtk_window_set_default_size (GTK_WINDOW (mux_main), 1024, 600);
gtk_widget_set_name (mux_main, gtk_widget_get_name (main));
gtk_widget_reparent (gtk_bin_get_child (GTK_BIN (main)), mux_main);
mux_window_set_decorations (MUX_WINDOW (mux_main), MUX_DECOR_SETTINGS|MUX_DECOR_CLOSE);
- g_signal_connect (mux_main, "settings-visibility-changed",
- G_CALLBACK (settings_visibility_changed_cb), data);
g_signal_connect (mux_main, "key-press-event",
G_CALLBACK (key_press_cb), data);
+ g_signal_connect (mux_main, "settings-visibility-changed",
+ G_CALLBACK (settings_visibility_changed_cb), data);
tmp = g_object_ref (gtk_bin_get_child (GTK_BIN (settings)));
gtk_container_remove (GTK_CONTAINER (settings), tmp);
- mux_window_append_page (MUX_WINDOW (mux_main),
- gtk_window_get_title (GTK_WINDOW (settings)),
- tmp,
- TRUE);
+ mux_window_append_page (MUX_WINDOW (mux_main), tmp, TRUE);
g_object_unref (tmp);
tmp = g_object_ref (gtk_bin_get_child (GTK_BIN (emergency)));
gtk_container_remove (GTK_CONTAINER (emergency), tmp);
data->emergency_index =
- mux_window_append_page (MUX_WINDOW (mux_main),
- gtk_window_get_title (GTK_WINDOW (emergency)),
- tmp,
- FALSE);
+ mux_window_append_page (MUX_WINDOW (mux_main), tmp, FALSE);
g_object_unref (tmp);
data->sync_win = mux_main;
app_data *data)
{
switch (response_id) {
+ case SYNC_ERROR_RESPONSE_SYNC:
+ start_sync (data);
+ break;
+ case SYNC_ERROR_RESPONSE_EMERGENCY_SLOW_SYNC:
+ slow_sync (data);
+ break;
case SYNC_ERROR_RESPONSE_EMERGENCY:
show_emergency_view (data);
break;
case SYNC_ERROR_RESPONSE_SETTINGS_OPEN:
data->open_current = TRUE;
- show_services_list (data);
+ show_services_list (data, NULL);
break;
case SYNC_ERROR_RESPONSE_SETTINGS_SELECT:
- show_services_list (data);
+ show_services_list (data, NULL);
break;
default:
g_warn_if_reached ();
}
}
+
+static void
+new_device_clicked_cb (GtkButton *btn, app_data *data)
+{
+ DBusGProxy *proxy;
+ DBusGConnection *bus;
+ char *argv[2] = {"bluetooth-wizard", NULL};
+ GError *error = NULL;
+
+ switch (data->bluetooth_wizard) {
+ case SYNC_BLUETOOTH_MOBLIN:
+
+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+ if (bus) {
+ proxy = dbus_g_proxy_new_for_name (bus,
+ "org.moblin.UX.Shell.Toolbar",
+ "/org/moblin/UX/Shell/Toolbar",
+ "org.moblin.UX.Shell.Toolbar");
+ dbus_g_proxy_call_no_reply (proxy, "ShowPanel",
+ G_TYPE_STRING, "bluetooth-panel",
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+ g_object_unref (proxy);
+ }
+ break;
+
+ case SYNC_BLUETOOTH_GNOME:
+ if (!gdk_spawn_on_screen (gtk_window_get_screen (GTK_WINDOW (data->sync_win)),
+ NULL,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ &error)) {
+ g_warning ("Failed to spawn bluetooth-wizard: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+static void
+name_has_owner_cb (DBusGProxy *proxy, gboolean has_owner,
+ GError *error, app_data *data)
+{
+ if (has_owner) {
+ gtk_widget_show (data->new_device_btn);
+ data->bluetooth_wizard = SYNC_BLUETOOTH_MOBLIN;
+ }
+ g_object_unref (proxy);
+}
+
+static void
+init_bluetooth_ui (app_data *data)
+{
+ char *bt_wizard;
+ DBusGConnection *bus;
+ DBusGProxy *proxy;
+
+ data->bluetooth_wizard = SYNC_BLUETOOTH_NONE;
+
+ /* look for gnome bluetooth wizard first */
+ bt_wizard = g_find_program_in_path ("bluetooth-wizard");
+ if (bt_wizard) {
+ gtk_widget_show (data->new_device_btn);
+ data->bluetooth_wizard = SYNC_BLUETOOTH_GNOME;
+ g_free (bt_wizard);
+ } else {
+ /* try Moblin shell next (bluetooth panel integrates bt wizard) */
+ bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
+ proxy = dbus_g_proxy_new_for_name (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+ if (proxy) {
+ org_freedesktop_DBus_name_has_owner_async (proxy,
+ "org.moblin.UX.Shell.Toolbar",
+ (org_freedesktop_DBus_name_has_owner_reply)name_has_owner_cb,
+ data);
+ }
+ }
+}
+
static gboolean
init_ui (app_data *data)
{
data->emergency_btn = GTK_WIDGET (gtk_builder_get_object (builder, "emergency_btn"));
data->sync_btn = GTK_WIDGET (gtk_builder_get_object (builder, "sync_btn"));
data->sync_status_label = GTK_WIDGET (gtk_builder_get_object (builder, "sync_status_label"));
+ data->spinner_image = GTK_WIDGET (gtk_builder_get_object (builder, "spinner_image"));
+ gtk_image_set_from_file (GTK_IMAGE (data->spinner_image), THEMEDIR "sync-spinner.gif");
+ gtk_widget_set_no_show_all (data->spinner_image, TRUE);
+ gtk_widget_hide (data->spinner_image);
data->server_label = GTK_WIDGET (gtk_builder_get_object (builder, "sync_service_label"));
data->last_synced_label = GTK_WIDGET (gtk_builder_get_object (builder, "last_synced_label"));
gtk_container_set_focus_vadjustment (GTK_CONTAINER (data->services_box), adj);
g_signal_connect(data->services_box, "size-allocate",
G_CALLBACK (services_box_allocate_cb), data);
+
+ data->devices_box = GTK_WIDGET (gtk_builder_get_object (builder, "devices_box"));
+
data->back_btn = GTK_WIDGET (gtk_builder_get_object (builder, "back_btn"));
/* emergency view */
btn = GTK_WIDGET (gtk_builder_get_object (builder, "slow_sync_btn"));
g_signal_connect (btn, "clicked",
G_CALLBACK (slow_sync_clicked_cb), data);
- data->emergency_from_server_btn = GTK_WIDGET (gtk_builder_get_object (builder, "refresh_from_server_btn"));
- g_signal_connect (data->emergency_from_server_btn, "clicked",
+ data->refresh_from_server_btn_label = GTK_WIDGET (gtk_builder_get_object (builder, "refresh_from_server_btn_label"));
+ g_signal_connect (GTK_WIDGET (gtk_builder_get_object (builder, "refresh_from_server_btn")), "clicked",
G_CALLBACK (refresh_from_server_clicked_cb), data);
- data->emergency_from_client_btn = GTK_WIDGET (gtk_builder_get_object (builder, "refresh_from_client_btn"));
- g_signal_connect (data->emergency_from_client_btn, "clicked",
+ data->refresh_from_client_btn_label = GTK_WIDGET (gtk_builder_get_object (builder, "refresh_from_client_btn_label"));
+ g_signal_connect (GTK_WIDGET (gtk_builder_get_object (builder, "refresh_from_client_btn")), "clicked",
G_CALLBACK (refresh_from_client_clicked_cb), data);
data->emergency_label = GTK_WIDGET (gtk_builder_get_object (builder, "emergency_label"));
data->emergency_expander = GTK_WIDGET (gtk_builder_get_object (builder, "emergency_expander"));
data->emergency_source_table = GTK_WIDGET (gtk_builder_get_object (builder, "emergency_source_table"));
+ data->emergency_backup_table = GTK_WIDGET (gtk_builder_get_object (builder, "emergency_backup_table"));
/* No (documented) way to add own widgets to gtkbuilder it seems...
swap the all dummy widgets with Muxwidgets */
g_signal_connect (data->sync_win, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
- g_signal_connect_swapped (data->back_btn, "clicked",
- G_CALLBACK (show_main_view), data);
g_signal_connect (data->change_service_btn, "clicked",
G_CALLBACK (change_service_clicked_cb), data);
g_signal_connect (data->emergency_btn, "clicked",
g_signal_connect (data->sync_btn, "clicked",
G_CALLBACK (sync_clicked_cb), data);
+ data->new_device_btn = GTK_WIDGET (gtk_builder_get_object (builder, "new_device_btn"));
+ g_signal_connect (data->new_device_btn, "clicked",
+ G_CALLBACK (new_device_clicked_cb), data);
+
+ init_bluetooth_ui (data);
+
g_object_unref (builder);
+
return TRUE;
}
gtk_widget_show (image);
}
+static void
+emergency_toggle_notify_active_cb (GtkWidget *widget,
+ gpointer p,
+ app_data *data)
+{
+ gboolean active;
+ char *source;
+
+ active = toggle_get_active (widget);
+ source = g_object_get_data (G_OBJECT (widget), "source");
+
+ g_return_if_fail (source);
+
+ if (active) {
+ g_hash_table_insert (data->emergency_sources, g_strdup (source), "");
+ } else {
+ g_hash_table_remove (data->emergency_sources, source);
+ }
+ update_emergency_expander (data);
+}
+
static GtkWidget*
add_emergency_toggle_widget (app_data *data,
const char *title,
col, col + 1, row, row + 1,
GTK_FILL, GTK_FILL, 16, 0);
toggle = mx_gtk_light_switch_new ();
+ toggle_set_active (toggle, active);
+ g_signal_connect (toggle, "switch-flipped",
+ G_CALLBACK (emergency_toggle_notify_active_cb), data);
#else
toggle = gtk_check_button_new_with_label (title);
+ toggle_set_active (toggle, active);
+ g_signal_connect (toggle, "notify::active",
+ G_CALLBACK (emergency_toggle_notify_active_cb), data);
#endif
- g_object_set (toggle, "active", active, NULL);
gtk_widget_show (toggle);
gtk_table_attach (GTK_TABLE (data->emergency_source_table), toggle,
col + 1, col + 2, row, row + 1,
* name, second a comma separeted list of sources.
* E.g. "Affected data: Google Contacts, Appointments" */
text = g_strdup_printf (_("Affected data: %s %s"),
- data->current_service->name,
+ data->current_service->pretty_name,
sources);
g_free (sources);
} else {
}
static void
-emergency_toggle_notify_active_cb (GtkWidget *widget,
- GParamSpec *pspec,
- app_data *data)
-{
- gboolean active;
- char *source;
-
- g_object_get (G_OBJECT (widget), "active", &active, NULL);
- source = g_object_get_data (G_OBJECT (widget), "source");
-
- g_return_if_fail (source);
-
- if (active) {
- g_hash_table_insert (data->emergency_sources, g_strdup (source), "");
- } else {
- g_hash_table_remove (data->emergency_sources, source);
- }
- update_emergency_expander (data);
-}
-
-
-static void
add_emergency_source (const char *name, source_config *conf, app_data *data)
{
GtkWidget *toggle;
pretty_name = get_pretty_source_name (name);
toggle = add_emergency_toggle_widget (data, pretty_name, active, row, col);
+ gtk_widget_set_sensitive (toggle, source_config_is_usable (conf));
g_object_set_data_full (G_OBJECT (toggle), "source", g_strdup (name), g_free);
g_free (pretty_name);
+}
- g_signal_connect (toggle, "notify::active",
- G_CALLBACK (emergency_toggle_notify_active_cb), data);
+static void
+update_backup_visibilities (app_data *data)
+{
+ char *key;
+ GHashTableIter iter;
+ GList *l, *widgets;
+
+ widgets = gtk_container_get_children (
+ GTK_CONTAINER (data->emergency_backup_table));
+ gtk_widget_show_all (data->emergency_backup_table);
+
+ /* hide backup widgets that do not contain selected sources */
+ g_hash_table_iter_init (&iter, data->emergency_sources);
+ while (g_hash_table_iter_next (&iter, (gpointer)&key, NULL)) {
+ for (l = widgets; l; l = l->next) {
+ if (!g_object_get_data (G_OBJECT (l->data), key)) {
+ gtk_widget_hide (GTK_WIDGET (l->data));
+ }
+ }
+ }
+
+ g_list_free (widgets);
+}
+
+static void
+restore_clicked_cb (GtkButton *btn, app_data *data)
+{
+ const char *dir, *time_str;
+ operation_data *op_data;
+ char *message;
+
+ dir = g_object_get_data (G_OBJECT (btn), "dir");
+ time_str = g_object_get_data (G_OBJECT (btn), "time");
+ g_return_if_fail (dir && time_str);
+
+ /* TRANSLATORS: confirmation for restoring a backup. placeholder is the
+ * backup time string defined below */
+ message = g_strdup_printf (_("Do you want to restore the backup from %s? "
+ "All changes you have made since then will be lost."),
+ time_str);
+ if (!show_confirmation (data->sync_win, message, _("Yes, restore"), _("No"))) {
+ g_free (message);
+ return;
+ }
+ g_free (message);
+
+ op_data = g_slice_new (operation_data);
+ op_data->data = data;
+ op_data->operation = OP_RESTORE;
+ op_data->dir = dir;
+ op_data->started = FALSE;
+ syncevo_server_start_session (data->server,
+ data->current_service->name,
+ (SyncevoServerStartSessionCb)start_session_cb,
+ op_data);
+
+ show_main_view (data);
+}
+
+static void
+add_backup (app_data *data, const char *peername, const char *dir,
+ long endtime, GList *sources)
+{
+ GtkWidget *timelabel, *label, *blabel, *button, *box;;
+ guint rows;
+ char *text;
+ char time_str[60];
+ struct tm *tim;
+
+ /* TRANSLATORS: date/time for strftime(), used in emergency view backup
+ * label. Any time format that shows date and time is good. */
+ tim = localtime (&endtime);
+ strftime (time_str, sizeof (time_str), _("%x %X"), tim);
+
+ g_object_get (data->emergency_backup_table,
+ "n-rows", &rows,
+ NULL);
+
+ box = gtk_vbox_new (TRUE, 6);
+ gtk_table_attach (GTK_TABLE (data->emergency_backup_table), box,
+ 0, 1, rows, rows + 1,
+ GTK_EXPAND|GTK_FILL, GTK_FILL, 16, 0);
+
+ timelabel = gtk_label_new (time_str);
+ gtk_misc_set_alignment (GTK_MISC (timelabel), 0.0, 0.5);
+ gtk_label_set_line_wrap (GTK_LABEL (timelabel), TRUE);
+ gtk_widget_set_size_request (timelabel, 600, -1);
+ gtk_box_pack_start_defaults (GTK_BOX (box), timelabel);
+
+ /* TRANSLATORS: label for a backup in emergency view. Placeholder is
+ * service or device name */
+ text = g_strdup_printf (_("Backed up before syncing with %s"), peername);
+ label = gtk_label_new (text);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_widget_set_size_request (label, 600, -1);
+ gtk_box_pack_start_defaults (GTK_BOX (box), label);
+ g_free (text);
+
+ button = gtk_button_new ();
+ gtk_table_attach (GTK_TABLE (data->emergency_backup_table), button,
+ 1, 2, rows, rows + 1,
+ GTK_FILL, GTK_SHRINK, 32, 0);
+ g_object_set_data_full (G_OBJECT (button), "dir", g_strdup(dir), g_free);
+ g_object_set_data_full (G_OBJECT (button), "time", g_strdup(time_str), g_free);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (restore_clicked_cb), data);
+
+ blabel = gtk_label_new (_("Restore"));
+ gtk_misc_set_padding (GTK_MISC (blabel), 32, 0);
+ gtk_container_add (GTK_CONTAINER (button), blabel);
+
+ for (; sources; sources = sources->next) {
+ g_object_set_data (G_OBJECT (box), (char *)sources->data, "");
+ g_object_set_data (G_OBJECT (button), (char *)sources->data, "");
+ }
+}
+
+static void
+get_reports_for_backups_cb (SyncevoServer *server,
+ SyncevoReports *reports,
+ GError *error,
+ app_data *data)
+{
+ guint len, i;
+
+ if (error) {
+ g_warning ("Error in Session.GetReports: %s", error->message);
+ g_error_free (error);
+ /* non-fatal, unknown error */
+ return;
+ }
+
+ len = syncevo_reports_get_length (reports);
+ for (i = 0; i < len; i++) {
+ GHashTable *report = syncevo_reports_index (reports, i);
+ GHashTableIter iter;
+ char *key, *val;
+ long status = -1;
+ long endtime = -1;
+ char *peername = NULL;
+ char *dir = NULL;
+ GList *backup_sources = NULL;
+
+ g_hash_table_iter_init (&iter, report);
+ while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&val)) {
+ char **strs;
+
+ strs = g_strsplit (key, "-", 6);
+ if (!strs) {
+ continue;
+ }
+
+ if (g_strcmp0 (strs[0], "source") == 0 &&
+ g_strcmp0 (strs[2], "backup") == 0 &&
+ g_strcmp0 (strs[3], "before") == 0) {
+ backup_sources = g_list_prepend (backup_sources,
+ g_strdup (strs[1]));
+ } else if (g_strcmp0 (strs[0], "end") == 0) {
+ endtime = strtol (val, NULL, 10);
+ } else if (g_strcmp0 (strs[0], "status") == 0) {
+ status = strtol (val, NULL, 10);
+ } else if (g_strcmp0 (strs[0], "peer") == 0) {
+ peername = val;
+ } else if (g_strcmp0 (strs[0], "dir") == 0) {
+ dir = val;
+ }
+ g_strfreev (strs);
+ }
+
+ if (peername && dir && endtime > 0) {
+ add_backup (data, peername, dir, endtime, backup_sources);
+ }
+ g_list_foreach (backup_sources, (GFunc)g_free, NULL);
+ g_list_free (backup_sources);
+ }
+
+ data->backup_count += len;
+ if (len == REPORTS_PER_CALL) {
+ syncevo_server_get_reports (data->server,
+ "",
+ data->backup_count, REPORTS_PER_CALL,
+ (SyncevoServerGetReportsCb)get_reports_for_backups_cb,
+ data);
+ }
+
+ update_backup_visibilities (data);
+}
+
+static const char*
+get_syncevo_context (const char *config_name)
+{
+ char *context;
+
+ context = g_strrstr (config_name, "@");
+ if (!context) {
+ context = "";
+ }
+ return context;
}
static void
text = g_strdup_printf (
/* TRANSLATORS: this is an explanation in Emergency view.
* Placeholder is a service/device name */
- _("A normal sync with %s is not possible at this time."
- "We can do a slow two-way sync, start from scratch or "
- "restore from backup."),
- data->current_service->name);
+ _("A normal sync with %s is not possible at this time. "
+ "You can do a slow two-way sync or start from scratch. You "
+ "can also restore a backup, but a slow sync or starting from "
+ "scratch will still be required before normal sync is "
+ "possible."),
+ data->current_service->pretty_name);
} else {
/* TRANSLATORS: this is an explanation in Emergency view.
* Placeholder is a service/device name */
text = g_strdup_printf (
- _("If something has gone horribly wrong with %s, we can try a "
- "slow sync, start from scratch or restore from backup."),
- data->current_service->name);
+ _("If something has gone horribly wrong, you can try a "
+ "slow sync, start from scratch or restore from backup."));
}
gtk_label_set_text (GTK_LABEL (data->emergency_label), text);
g_free (text);
text = g_strdup_printf (_("Delete all your local\n"
"data and replace with\n"
"data from %s"),
- data->current_service->name);
- gtk_button_set_label (GTK_BUTTON (data->emergency_from_server_btn), text);
+ data->current_service->pretty_name);
+ gtk_label_set_text (GTK_LABEL (data->refresh_from_server_btn_label), text);
g_free (text);
text = g_strdup_printf (_("Delete all data on\n"
"%s and replace\n"
"with your local data"),
- data->current_service->name);
- gtk_button_set_label (GTK_BUTTON (data->emergency_from_client_btn), text);
+ data->current_service->pretty_name);
+ gtk_label_set_text (GTK_LABEL (data->refresh_from_client_btn_label), text);
g_free (text);
gtk_container_foreach (GTK_CONTAINER (data->emergency_source_table),
(GHFunc)add_emergency_source,
data);
update_emergency_expander (data);
+
+ data->backup_count = 0;
+ gtk_container_foreach (GTK_CONTAINER (data->emergency_backup_table),
+ (GtkCallback)remove_child,
+ data->emergency_backup_table);
+ gtk_table_resize (GTK_TABLE (data->emergency_backup_table), 1, 1);
+ syncevo_server_get_reports (data->server,
+ get_syncevo_context (data->current_service->name),
+ 0, REPORTS_PER_CALL,
+ (SyncevoServerGetReportsCb)get_reports_for_backups_cb,
+ data);
+
}
static void
update_service_source_ui (const char *name, source_config *conf, app_data *data)
{
GtkWidget *lbl, *box;
- char *pretty_name;
- const char *source_uri, *sync;
+ char *pretty_name, *title;
- source_uri = g_hash_table_lookup (conf->config, "uri");
- sync = g_hash_table_lookup (conf->config, "sync");
-
- if (!sync ||
- strcmp (sync, "disabled") == 0 ||
- strcmp (sync, "none") == 0 ||
- !source_uri ||
- strlen (source_uri) == 0 ||
- !conf->supported_locally) {
+ if (!source_config_is_usable (conf)) {
return;
}
gtk_box_pack_start (GTK_BOX (data->sources_box), conf->box,
FALSE, FALSE, 8);
- pretty_name = get_pretty_source_name (name);
- lbl = gtk_label_new (pretty_name);
+ pretty_name = get_pretty_source_name_markup (name);
+ title = g_strdup_printf ("<b>%s</b>", pretty_name);
+ lbl = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (lbl), title);
g_free (pretty_name);
+ g_free (title);
gtk_misc_set_alignment (GTK_MISC (lbl), 0.0, 0.5);
gtk_box_pack_start_defaults (GTK_BOX (conf->box), lbl);
refresh_last_synced_label (data);
-/* TODO: make sure all default sources are visible
- * (iow add missing sources as insensitive) */
-
gtk_widget_show_all (data->sources_box);
}
}
}
-static GtkWidget*
-add_server_to_box (GtkBox *box,
- const char *name,
- gboolean configured,
- gboolean has_template,
- app_data *data)
+static SyncConfigWidget*
+add_configuration_to_box (GtkBox *box,
+ SyncevoConfig *config,
+ const char *name,
+ gboolean has_template,
+ gboolean has_configuration,
+ app_data *data)
{
GtkWidget *item = NULL;
gboolean current = FALSE;
const char *current_name = NULL;
if (data->current_service) {
- current_name = data->current_service->name;
+ current_name = data->current_service->pretty_name;
if (data->current_service->name && name &&
- strcmp (name, data->current_service->name) == 0) {
+ g_strcasecmp (name, data->current_service->name) == 0) {
current = TRUE;
}
}
item = sync_config_widget_new (data->server, name,
+ config,
current, current_name,
- configured, has_template);
+ has_configuration, has_template);
g_signal_connect (item, "changed",
G_CALLBACK (config_widget_changed_cb), data);
g_signal_connect (item, "notify::expanded",
if (current) {
sync_config_widget_set_expanded (SYNC_CONFIG_WIDGET (item),
data->open_current);
- data->open_current = FALSE;
}
+ if (g_strcmp0 (name, "default") == 0) {
+ sync_config_widget_set_expanded (SYNC_CONFIG_WIDGET (item),
+ TRUE);
+ }
+
+ if (data->config_id_to_open) {
+ sync_config_widget_expand_id (SYNC_CONFIG_WIDGET (item),
+ data->config_id_to_open);
+ }
+
+ return SYNC_CONFIG_WIDGET (item);
- return item;
}
static void
}
}
+typedef struct config_data {
+ app_data *data;
+ char *name;
+ gboolean has_configuration;
+ gboolean has_template;
+ GHashTable *device_templates;
+
+} config_data;
+
+static void
+get_config_for_config_widget_cb (SyncevoServer *server,
+ SyncevoConfig *config,
+ GError *error,
+ config_data *c_data)
+{
+ char *ready, *is_peer, *url;
+
+ if (error) {
+ /* show in UI? */
+ g_warning ("Server.GetConfig() failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ syncevo_config_get_value (config, NULL, "ConsumerReady", &ready);
+ syncevo_config_get_value (config, NULL, "PeerIsClient", &is_peer);
+ syncevo_config_get_value (config, NULL, "syncURL", &url);
+
+ if (is_peer && g_strcmp0 ("1", is_peer) == 0) {
+ if (url) {
+ SyncConfigWidget *w;
+ char *fp, *device_name = NULL;
+ char **fpv = NULL;
+
+ /* NOTE: using device_name here means a new config will be saved with
+ * device_name (and not the template name). Not sure if this is
+ * what we really want... */
+ syncevo_config_get_value (config, NULL, "fingerPrint", &fp);
+
+ if (fp) {
+ fpv = g_strsplit_set (fp, ",;", 2);
+ if (g_strv_length (fpv) > 0) {
+ device_name = fpv[0];
+ }
+ }
+ if (!device_name) {
+ device_name = c_data->name;
+ }
+
+ /* keep a list of added devices */
+ w = g_hash_table_lookup (c_data->device_templates, url);
+ if (!w) {
+ if (c_data->has_configuration || g_strcmp0 ("1", ready) == 0) {
+ w = add_configuration_to_box (GTK_BOX (c_data->data->devices_box),
+ config,
+ device_name,
+ c_data->has_template,
+ c_data->has_configuration,
+ c_data->data);
+ g_hash_table_insert (c_data->device_templates, url, w);
+ }
+ } else {
+ /* TODO: might want to add a new widget, if user has created more
+ * configs for same device: this really requires us to look at
+ * all configs / templates, then decide what to sho w*/
+
+ /* there is a widget for this device already, add this info there*/
+ sync_config_widget_add_alternative_config (w, device_name, config,
+ c_data->has_configuration);
+ }
+
+ g_strfreev (fpv);
+ }
+ } else {
+ if (c_data->has_configuration || g_strcmp0 ("1", ready) == 0) {
+ add_configuration_to_box (GTK_BOX (c_data->data->services_box),
+ config,
+ c_data->name,
+ c_data->has_template,
+ c_data->has_configuration,
+ c_data->data);
+ }
+ }
+
+ g_free (c_data->name);
+ g_hash_table_unref (c_data->device_templates);
+ g_slice_free (config_data, c_data);
+}
+
+static void
+get_config_for_config_widget (app_data *data,
+ const char *config,
+ gboolean has_template,
+ gboolean has_configuration,
+ GHashTable *device_templates)
+
+{
+ config_data *c_data;
+
+ c_data = g_slice_new0 (config_data);
+ c_data->data = data;
+ c_data->name = g_strdup (config);
+ c_data->has_template = has_template;
+ c_data->has_configuration = has_configuration;
+ if (device_templates) {
+ c_data->device_templates = g_hash_table_ref (device_templates);
+ }
+
+ syncevo_server_get_config (data->server,
+ config,
+ !has_configuration,
+ (SyncevoServerGetConfigCb)get_config_for_config_widget_cb,
+ c_data);
+}
+
static void
setup_new_service_clicked (GtkButton *btn, app_data *data)
{
(GtkCallback)find_new_service_config,
&widget);
if (!widget) {
- widget = add_server_to_box (GTK_BOX (data->services_box),
- "default",
- FALSE, TRUE,
- data);
+ get_config_for_config_widget (data, "default", TRUE, FALSE, NULL);
+ } else {
+ sync_config_widget_set_expanded (SYNC_CONFIG_WIDGET (widget), TRUE);
}
- sync_config_widget_set_expanded (SYNC_CONFIG_WIDGET (widget), TRUE);
}
-
typedef struct templates_data {
app_data *data;
char **templates;
{
char **config_iter, **template_iter, **templates;
app_data *data;
- GtkWidget *widget;
+ GHashTable *device_templates;
templates = templ_data->templates;
data = templ_data->data;
if (error) {
show_main_view (data);
- /* TODO show in UI: failed to show service list */
g_warning ("Server.GetConfigs() failed: %s", error->message);
g_strfreev (templates);
g_error_free (error);
return;
}
+ device_templates = g_hash_table_new (g_str_hash, g_str_equal);
+
for (template_iter = templates; *template_iter; template_iter++){
gboolean found_config = FALSE;
for (config_iter = configs; *config_iter; config_iter++) {
- if (*template_iter &&
- *config_iter &&
+ if (*template_iter && *config_iter &&
g_ascii_strncasecmp (*template_iter,
*config_iter,
strlen (*config_iter)) == 0) {
- widget = add_server_to_box (GTK_BOX (data->services_box),
- *template_iter,
- TRUE, TRUE,
- data);
+ /* have template and config */
+ get_config_for_config_widget (data, *config_iter,
+ TRUE, TRUE, device_templates);
found_config = TRUE;
break;
}
}
if (!found_config) {
- widget = add_server_to_box (GTK_BOX (data->services_box),
- *template_iter,
- FALSE, TRUE,
- data);
+ /* have template, no config */
+ get_config_for_config_widget (data, *template_iter,
+ TRUE, FALSE, device_templates);
}
}
}
}
if (!found_template) {
- widget = add_server_to_box (GTK_BOX (data->services_box),
- *config_iter,
- TRUE, FALSE,
- data);
+ /* have config, no template */
+ get_config_for_config_widget (data, *config_iter,
+ FALSE, TRUE, device_templates);
}
}
+ /* config initialization might ref/unref as well... */
+ g_hash_table_unref (device_templates);
g_strfreev (configs);
g_strfreev (templates);
}
if (error) {
show_main_view (data);
- /* TODO show in UI: failed to show service list */
+
show_error_dialog (data->sync_win,
_("Failed to get list of supported services from SyncEvolution"));
g_warning ("Server.GetConfigs() failed: %s", error->message);
static void
update_services_list (app_data *data)
{
- /* NOTE: could get this on ui startup as well for instant action.
- Downside is stale data.... */
-
gtk_container_foreach (GTK_CONTAINER (data->services_box),
(GtkCallback)remove_child,
data->services_box);
+ gtk_container_foreach (GTK_CONTAINER (data->devices_box),
+ (GtkCallback)remove_child,
+ data->devices_box);
syncevo_server_get_configs (data->server,
TRUE,
}
static void
-set_running_session_status (app_data *data, SyncevoSessionStatus status)
+set_running_session_status (app_data *data,
+ SyncevoSessionStatus status,
+ int error_code)
{
- switch (status) {
- case SYNCEVO_STATUS_QUEUEING:
+ if (status & SYNCEVO_STATUS_QUEUEING) {
g_warning ("Running session is queued, this shouldn't happen...");
- break;
- case SYNCEVO_STATUS_IDLE:
+ } else if (status & SYNCEVO_STATUS_IDLE) {
set_app_state (data, SYNC_UI_STATE_SERVER_OK);
- break;
- case SYNCEVO_STATUS_RUNNING:
- case SYNCEVO_STATUS_SUSPENDING:
- case SYNCEVO_STATUS_ABORTING:
- set_app_state (data, SYNC_UI_STATE_SYNCING);
- break;
- case SYNCEVO_STATUS_DONE:
- gtk_label_set_text (GTK_LABEL (data->sync_status_label),
- _("Sync complete"));
+ } else if (status & SYNCEVO_STATUS_DONE) {
+ char *err;
+ err = get_error_string_for_code (error_code, NULL);
+ if (err) {
+ if (data->current_operation == OP_RESTORE) {
+ gtk_label_set_text (GTK_LABEL (data->sync_status_label),
+ _("Restore failed"));
+ } else {
+ gtk_label_set_text (GTK_LABEL (data->sync_status_label),
+ _("Sync failed"));
+ }
+ g_free (err);
+ } else {
+ if (data->current_operation == OP_RESTORE) {
+ gtk_label_set_text (GTK_LABEL (data->sync_status_label),
+ _("Restore complete"));
+ } else {
+ gtk_label_set_text (GTK_LABEL (data->sync_status_label),
+ _("Sync complete"));
+ }
+ }
set_app_state (data, SYNC_UI_STATE_SERVER_OK);
set_sync_progress (data, 1.0, "");
-
- break;
- default:
- g_warning ("unknown session status %d used!", status);
- }
-}
-
-static void
-update_source_status (char *name,
- SyncevoSyncMode mode,
- SyncevoSourceStatus status,
- guint error_code,
- app_data *data)
-{
- char *error;
- static char *waiting_source = NULL;
-
- error = get_error_string_for_code (error_code, NULL);
- if (error) {
- /* TODO show sync error in UI -- but not duplicates */
- g_warning ("Source '%s' error: %s", name, error);
- g_free (error);
+ } else if (status & SYNCEVO_STATUS_RUNNING ||
+ status & SYNCEVO_STATUS_SUSPENDING ||
+ status & SYNCEVO_STATUS_ABORTING) {
+ set_app_state (data, SYNC_UI_STATE_SYNCING);
}
- if (status & SYNCEVO_SOURCE_WAITING) {
- g_free (waiting_source);
- waiting_source = g_strdup (name);
- /* TODO: start spinner */
- } else if (waiting_source && strcmp (waiting_source, name) == 0) {
- g_free (waiting_source);
- waiting_source = NULL;
- /* TODO: stop spinner */
+ if (status & SYNCEVO_STATUS_WAITING) {
+ gtk_widget_show (data->spinner_image);
+ } else {
+ gtk_widget_hide (data->spinner_image);
}
}
SyncevoSourceStatuses *source_statuses,
app_data *data)
{
- set_running_session_status (data, status);
-
- syncevo_source_statuses_foreach (source_statuses,
- (SourceStatusFunc)update_source_status,
- data);
+ set_running_session_status (data, status, error_code);
}
static void
return;
}
- set_running_session_status (data, status);
+ set_running_session_status (data, status, error_code);
+}
+
+typedef struct source_progress_data {
+ app_data *data;
+ SyncevoSourcePhase phase;
+ const char *source;
+} source_progress_data;
+
+static void
+find_updated_source_progress (const char *name,
+ SyncevoSourcePhase phase,
+ source_progress_data *prog_data)
+{
+ GHashTable *configs = prog_data->data->current_service->source_configs;
+ source_config *config;
+ config = g_hash_table_lookup (configs, name);
+ if (config) {
+ if (phase != config->phase) {
+ config->phase = phase;
+ prog_data->phase = config->phase;
+ prog_data->source = name;
+ }
+ }
}
static void
SyncevoSourceProgresses *source_progresses,
app_data *data)
{
- SyncevoSourceProgress *s_progress;
- char *name;
- char *msg = NULL;
-
- s_progress = syncevo_source_progresses_get_current (source_progresses);
- if (!s_progress) {
- return;
- }
+ source_progress_data *prog_data = g_slice_new0 (source_progress_data);
+ prog_data->data = data;
+ prog_data->phase = SYNCEVO_PHASE_NONE;
+ prog_data->source = NULL;
- name = get_pretty_source_name (s_progress->name);
+ syncevo_source_progresses_foreach (source_progresses,
+ (SourceProgressFunc)find_updated_source_progress,
+ prog_data);
+ if (!prog_data->source) {
+ set_sync_progress (data, ((float)progress) / 100, NULL);
+ } else {
+ char *name;
+ char *msg = NULL;
- switch (s_progress->phase) {
- case SYNCEVO_PHASE_PREPARING:
- msg = g_strdup_printf (_("Preparing '%s'"), name);
- break;
- case SYNCEVO_PHASE_RECEIVING:
- msg = g_strdup_printf (_("Receiving '%s'"), name);
- break;
- case SYNCEVO_PHASE_SENDING:
- msg = g_strdup_printf (_("Sending '%s'"), name);
- break;
- default:
- ;
- }
- g_free (name);
+ name = get_pretty_source_name (prog_data->source);
+ switch (prog_data->phase) {
+ case SYNCEVO_PHASE_PREPARING:
+ msg = g_strdup_printf (_("Preparing '%s'"), name);
+ break;
+ case SYNCEVO_PHASE_RECEIVING:
+ msg = g_strdup_printf (_("Receiving '%s'"), name);
+ break;
+ case SYNCEVO_PHASE_SENDING:
+ msg = g_strdup_printf (_("Sending '%s'"), name);
+ break;
+ default:
+ ;
+ }
- if (msg) {
- set_sync_progress (data, ((float)progress) / 100, msg);
+ if (msg) {
+ set_sync_progress (data, ((float)progress) / 100, msg);
+ }
g_free (msg);
+ g_free (name);
+
}
- syncevo_source_progress_free (s_progress);
+ g_slice_free (source_progress_data, prog_data);
}
typedef struct source_stats {
return TRUE;
}
- /* TODO improve error visibility */
msg = get_error_string_for_code (source->status, &response);
if (msg) {
show_error = TRUE;
char *error_msg;
SyncErrorResponse response;
gboolean have_source_errors;
+ GHashTable *report = NULL;
+ guint len;
if (error) {
g_warning ("Error in Session.GetReports: %s", error->message);
sources = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify)free_source_stats);
+ len = syncevo_reports_get_length (reports);
- if (syncevo_reports_get_length (reports) > 0) {
- GHashTable *report = syncevo_reports_index (reports, 0);
+ if (len > 0) {
+ report = syncevo_reports_index (reports, 0);
+ val = g_hash_table_lookup (report, "dir");
+ if (!val || strlen (val) == 0) {
+ /* dummy report for first time sync info*/
+ if (len > 1) {
+ report = syncevo_reports_index (reports, 1);
+ } else {
+ report = NULL;
+ }
+ }
+ }
+ if (report) {
g_hash_table_iter_init (&iter, report);
while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&val)) {
char **strs;
}
}
+ if (status != 200) {
+ /* don't want to show a sync time for failed syncs */
+ data->last_sync = -1;
+ }
+
if (!data->forced_emergency) {
/* if user initiates a emergency sync wihtout forced_emergency,
enable all sources by default*/
- g_hash_table_iter_init (&iter, sources);
- while (g_hash_table_iter_next (&iter, (gpointer)&key, NULL)) {
- g_hash_table_insert (data->emergency_sources,
- g_strdup (key), "");
+ g_hash_table_iter_init (&iter, data->current_service->source_configs);
+ while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&source_conf)) {
+ if (source_config_is_usable (source_conf)) {
+ g_hash_table_insert (data->emergency_sources, g_strdup (key), "");
+ }
}
}
/* update service UI */
refresh_last_synced_label (data);
if (error_msg) {
+ GtkMessageType type = GTK_MESSAGE_ERROR;
+
+ if (response == SYNC_ERROR_RESPONSE_EMERGENCY) {
+ type = GTK_MESSAGE_QUESTION;
+ }
+
+ set_info_bar (data->info_bar, type, response, error_msg);
+ g_free (error_msg);
+ } else if (data->current_operation == OP_RESTORE) {
+ /* special case for just after restoring */
+ error_msg = g_strdup_printf
+ (_("You've just restored a backup. The changes have not been "
+ "synced with %s yet"), data->current_service->pretty_name);
set_info_bar (data->info_bar,
- GTK_MESSAGE_ERROR, response,
+ GTK_MESSAGE_INFO,
+ SYNC_ERROR_RESPONSE_SYNC,
error_msg);
- g_free (error_msg);
}
g_hash_table_destroy (sources);
}
static void
+restore_cb (SyncevoSession *session,
+ GError *error,
+ app_data *data)
+{
+ if (error) {
+ g_warning ("Error in Session.Restore: %s", error->message);
+ g_error_free (error);
+
+ return;
+ }
+}
+
+static void
+restore_backup (app_data *data, SyncevoSession *session, const char *dir)
+{
+ char **sources;
+ GHashTableIter iter;
+ int i = 0;
+ char *source;
+
+ sources = g_malloc0 (sizeof (char*) *
+ (g_hash_table_size (data->emergency_sources) + 1));
+
+ g_hash_table_iter_init (&iter, data->emergency_sources);
+ while (g_hash_table_iter_next (&iter, (gpointer)&source, NULL)) {
+ sources[i++] = g_strdup (source);
+ }
+ sources[i] = NULL;
+
+ syncevo_session_restore (session, dir, TRUE, (const char**)sources,
+ (SyncevoSessionGenericCb)restore_cb,
+ data);
+
+ g_strfreev (sources);
+}
+
+static void
save_config (app_data *data, SyncevoSession *session)
{
syncevo_session_set_config (session,
return;
}
op_data->started = TRUE;
+ op_data->data->current_operation = op_data->operation;
/* time for business */
switch (op_data->operation) {
case OP_SAVE:
save_config (op_data->data, session);
break;
+ case OP_RESTORE:
+ restore_backup (op_data->data, session, op_data->dir);
+ break;
default:
g_warn_if_reached ();
}
mux_window_set_current_page (MUX_WINDOW (data->sync_win),
data->emergency_index);
#else
+ gtk_widget_hide (data->services_win);
gtk_window_present (GTK_WINDOW (data->emergency_win));
#endif
}
static void
-show_services_list (app_data *data)
+show_services_list (app_data *data, const char *config_id_to_open)
{
+ g_free (data->config_id_to_open);
+ data->config_id_to_open = g_strdup (config_id_to_open);
+
#ifdef USE_MOBLIN_UX
mux_window_set_settings_visible (MUX_WINDOW (data->sync_win), TRUE);
#else
+ gtk_widget_hide (data->emergency_win);
gtk_window_present (GTK_WINDOW (data->services_win));
update_services_list (data);
#endif
mux_window_set_current_page (MUX_WINDOW (data->sync_win), -1);
#else
gtk_widget_hide (data->services_win);
+ gtk_widget_hide (data->emergency_win);
#endif
gtk_window_present (GTK_WINDOW (data->sync_win));
}
if (response) {
*response = SYNC_ERROR_RESPONSE_EMERGENCY;
}
- return g_strdup (_("A normal sync is not possible at this time. You "
- "will need to fix things before we can sync again."));
+ return g_strdup (_("A normal sync is not possible at this time. The server "
+ "suggests a slow sync, but this might not always be "
+ "what you want if both ends already have data."));
+ case 22002:
+ return g_strdup (_("The sync service died unexpectedly."));
case DB_Unauthorized:
if (response) {
*response = SYNC_ERROR_RESPONSE_SETTINGS_OPEN;
return g_strdup(_("The source could not be found. Could there be a "
"problem with the server settings?"));
case DB_Fatal:
- /* This can happen when EDS is borked, restart may help... */
return g_strdup(_("Fatal database error"));
+ case LOCAL_STATUS_CODE + DB_Fatal:
+ /* This can happen when EDS is borked, restart it may help... */
+ return g_strdup(_("There is a problem with the local database. "
+ "Syncing again or rebooting may help."));
case DB_Error:
return g_strdup(_("Database error"));
case DB_Full:
}
static void
+password_dialog_response_cb (GtkWidget *dialog, int response, app_data *data)
+{
+ const char *password;
+ GHashTable *return_dict;
+
+ return_dict = g_hash_table_new (g_str_hash, g_str_equal);
+
+ if (response == GTK_RESPONSE_OK) {
+ password = gtk_entry_get_text (GTK_ENTRY (data->password_dialog_entry));
+ g_hash_table_insert (return_dict, "password", (gpointer)password);
+ }
+
+ syncevo_server_info_response (data->server, data->password_dialog_id,
+ "response", return_dict, NULL, NULL);
+
+ g_hash_table_destroy (return_dict);
+
+ g_free (data->password_dialog_id);
+ data->password_dialog_id = NULL;
+ gtk_widget_destroy (dialog);
+}
+
+static void
info_request_cb (SyncevoServer *syncevo,
char *id,
char *session_path,
char *state,
char *handler_path,
char *type,
+ GHashTable *parameters,
app_data *data)
{
- /* Implementation waiting for moblin bug #6376*/
- g_warning ("InfoRequest handler not implemented yet");
+ GHashTable *t;
+ GtkWidget *dialog, *content, *label, *align;
+ char *msg;
+
+ if (g_strcmp0 (state, "request") != 0 ||
+ g_strcmp0 (type, "password") != 0) {
+ /* not handling other stuff */
+ return;
+ }
+
+ if (!data->running_session ||
+ g_strcmp0 (session_path,
+ syncevo_session_get_path (data->running_session)) != 0) {
+ /* not our problem */
+ return;
+ }
+
+ t = g_hash_table_new (g_str_hash, g_str_equal);
+ syncevo_server_info_response (syncevo, id, "working", t, NULL, NULL);
+ g_hash_table_destroy (t);
+
+ data->password_dialog_id = g_strdup (id);
+
+ /* TRANSLATORS: password request dialog contents: title, cancel button
+ * and ok button */
+ dialog = gtk_dialog_new_with_buttons (_("Password is required for sync"),
+ GTK_WINDOW (data->sync_win),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ _("Cancel sync"), GTK_RESPONSE_CANCEL,
+ _("Sync with password"), GTK_RESPONSE_OK,
+ NULL);
+ content = GTK_DIALOG (dialog)->vbox;
+
+ align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 16, 16);
+ gtk_widget_show (align);
+ gtk_box_pack_start (GTK_BOX (content), align, FALSE, FALSE, 6);
+
+ /* TRANSLATORS: password request dialog message, placeholder is service name */
+ msg = g_strdup_printf (_("Please enter password for syncing with %s:"),
+ data->current_service->pretty_name);
+ label = gtk_label_new (msg);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_widget_set_size_request (label, 500, -1);
+
+ gtk_widget_show (label);
+ gtk_container_add (GTK_CONTAINER (align), label);
+ g_free (msg);
+
+ align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 16, 16);
+ gtk_widget_show (align);
+ gtk_box_pack_start (GTK_BOX (content), align, FALSE, FALSE, 6);
+
+ data->password_dialog_entry = gtk_entry_new_with_max_length (99);
+ gtk_entry_set_width_chars (GTK_ENTRY (data->password_dialog_entry), 30);
+ gtk_entry_set_visibility (GTK_ENTRY (data->password_dialog_entry), FALSE);
+
+ gtk_widget_show (data->password_dialog_entry);
+ gtk_container_add (GTK_CONTAINER (align), data->password_dialog_entry);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (password_dialog_response_cb), data);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+ gtk_widget_grab_focus (data->password_dialog_entry);
}
static void
}
static void
+server_templates_changed_cb (SyncevoServer *server,
+ app_data *data)
+{
+ if (GTK_WIDGET_VISIBLE (data->services_box)) {
+ update_services_list (data);
+ }
+}
+
+static void
server_session_changed_cb (SyncevoServer *server,
char *path,
gboolean started,
syncevo_config_free (config);
}
-GtkWidget*
-sync_ui_create_main_window ()
+app_data*
+sync_ui_create ()
{
app_data *data;
G_CALLBACK (server_session_changed_cb), data);
g_signal_connect (data->server, "presence_changed",
G_CALLBACK (server_presence_changed_cb), data);
+ g_signal_connect (data->server, "templates_changed",
+ G_CALLBACK (server_templates_changed_cb), data);
g_signal_connect (data->server, "info-request",
G_CALLBACK (info_request_cb), data);
gtk_window_present (GTK_WINDOW (data->sync_win));
- return data->sync_win;
+ return data;
+}
+
+void sync_ui_show_settings (app_data *data, const char *id)
+{
+ show_services_list (data, id);
+}
+
+GtkWindow*
+sync_ui_get_main_window (app_data *data)
+{
+ return GTK_WINDOW(data->sync_win);
}
#define SYNC_UI_LIST_ICON_SIZE 32
#define SYNC_UI_LIST_BTN_WIDTH 150
+typedef struct _app_data app_data;
+
typedef enum SyncErrorResponse {
SYNC_ERROR_RESPONSE_NONE,
+ SYNC_ERROR_RESPONSE_SYNC,
SYNC_ERROR_RESPONSE_SETTINGS_SELECT,
SYNC_ERROR_RESPONSE_SETTINGS_OPEN,
SYNC_ERROR_RESPONSE_EMERGENCY,
+ SYNC_ERROR_RESPONSE_EMERGENCY_SLOW_SYNC,
} SyncErrorResponse;
char* get_pretty_source_name (const char *source_name);
char* get_error_string_for_code (int error_code, SyncErrorResponse *response);
void show_error_dialog (GtkWidget *widget, const char* message);
+gboolean show_confirmation (GtkWidget *widget, const char *message, const char *yes, const char *no);
+
+app_data *sync_ui_create ();
+GtkWindow *sync_ui_get_main_window (app_data *data);
+void sync_ui_show_settings (app_data *data, const char *id);
-GtkWidget* sync_ui_create_main_window ();
+void toggle_set_active (GtkWidget *toggle, gboolean active);
+gboolean toggle_get_active (GtkWidget *toggle);
#endif
<!-- interface-requires gtk+ 2.10 -->
<!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="sync_win">
+ <property name="width_request">1024</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Sync</property>
<property name="default_width">800</property>
<property name="xalign">0</property>
<property name="yalign">0.80000001192092896</property>
<property name="use_markup">True</property>
+ <property name="ellipsize">end</property>
+ <property name="max_width_chars">45</property>
</widget>
<packing>
<property name="expand">False</property>
</widget>
</child>
<child>
- <widget class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="xpad">5</property>
- <property name="label" translatable="yes"><b>Data</b></property>
- <property name="use_markup">True</property>
- </widget>
+ <placeholder/>
<packing>
<property name="type">label_item</property>
</packing>
</widget>
<packing>
<property name="expand">False</property>
+ <property name="fill">False</property>
<property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
+ <child>
+ <widget class="GtkVBox" id="spinner_box">
+ <property name="height_request">24</property>
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <widget class="GtkImage" id="spinner_image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-missing-image</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
- <child>
- <widget class="GtkHBox" id="hbox8">
- <property name="visible">True</property>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
</widget>
<packing>
<property name="expand">False</property>
<widget class="GtkHBox" id="hbox20">
<property name="visible">True</property>
<child>
- <widget class="GtkVBox" id="vbox19">
- <property name="height_request">30</property>
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
<widget class="GtkVBox" id="info_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="position">0</property>
</packing>
</child>
- <child>
- <widget class="GtkHBox" id="errors_box">
- <property name="spacing">5</property>
- <child>
- <widget class="GtkImage" id="error_img">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="stock">gtk-dialog-error</property>
- <property name="icon-size">5</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <widget class="GtkVBox" id="error_box">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">1</property>
- </packing>
- </child>
</widget>
<packing>
<property name="expand">False</property>
<property name="padding">5</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
</widget>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
+ <widget class="GtkLabel" id="action_label">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="title for the buttons on the right side of main view"><b>Actions</b></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
<widget class="GtkButton" id="sync_btn">
<property name="label">Sync now</property>
<property name="visible">True</property>
</widget>
<packing>
<property name="fill">False</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
</widget>
<packing>
<property name="fill">False</property>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkWindow" id="services_win">
+ <property name="width_request">1024</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Settings</property>
<property name="modal">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
- <widget class="GtkHBox" id="hbox4">
+ <widget class="GtkScrolledWindow" id="settings_scrolledwindow">
<property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <widget class="GtkVBox" id="vbox7">
+ <widget class="GtkViewport" id="settings_viewport">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="resize_mode">queue</property>
<child>
- <widget class="GtkVBox" id="vbox13">
+ <widget class="GtkHBox" id="hbox4">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">5</property>
- <child>
- <widget class="GtkLabel" id="label8">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes"><big>Supported services</big></property>
- <property name="use_markup">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox11">
- <property name="visible">True</property>
- <child>
- <widget class="GtkLabel" id="label5">
- <property name="visible">True</property>
- <property name="label" translatable="yes">To sync you'll need a network connection and an account with a sync service.
-We support the following services: </property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">1</property>
- </packing>
- </child>
<child>
- <widget class="GtkScrolledWindow" id="scrolledwindow">
+ <widget class="GtkAlignment" id="alignment_1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="bottom_padding">12</property>
+ <property name="left_padding">36</property>
+ <property name="right_padding">12</property>
<child>
- <widget class="GtkViewport" id="viewport1">
+ <widget class="GtkVBox" id="vbox7">
<property name="visible">True</property>
- <property name="resize_mode">queue</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
<child>
- <widget class="GtkVBox" id="services_box">
+ <widget class="GtkVBox" id="vbox13">
<property name="visible">True</property>
<property name="orientation">vertical</property>
+ <property name="spacing">5</property>
<child>
- <placeholder/>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><big>Network sync</big></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
</child>
<child>
- <placeholder/>
+ <widget class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">To sync you'll need a network connection and an account with a sync service.
+We support the following services: </property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow">
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="resize_mode">queue</property>
+ <child>
+ <widget class="GtkVBox" id="services_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox14">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">If you don't see your service above but know that your sync provider uses SyncML
+you can setup a service manually.</property>
+ </widget>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="new_service_btn">
+ <property name="label" translatable="yes">Add new service</property>
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">8</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
</child>
</widget>
+ <packing>
+ <property name="padding">8</property>
+ <property name="position">0</property>
+ </packing>
</child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">8</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <widget class="GtkVBox" id="vbox12">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">5</property>
- <child>
- <widget class="GtkLabel" id="label7">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes"><big>Manual setup</big></property>
- <property name="use_markup">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox14">
- <property name="visible">True</property>
- <child>
- <widget class="GtkLabel" id="label6">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">If you don't see your service above but know that your sync provider uses SyncML
-you can setup a service manually.</property>
- </widget>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <widget class="GtkButton" id="new_service_btn">
- <property name="label" translatable="yes">Add new service</property>
- <property name="width_request">150</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="padding">8</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="padding">8</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox1">
- <property name="visible">True</property>
- <child>
- <widget class="GtkButton" id="back_btn">
- <property name="label" translatable="yes">Back to sync</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="padding">16</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
+ <child>
+ <widget class="GtkVBox" id="direct_sync_box">
+ <property name="height_request">400</property>
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">5</property>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><big>Direct sync</big></property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Use Bluetooth to Sync your data from one device to another.</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="device_scrolledwindow">
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <widget class="GtkViewport" id="viewport2">
+ <property name="visible">True</property>
+ <property name="resize_mode">queue</property>
+ <child>
+ <widget class="GtkVBox" id="devices_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="add_bt_device_box">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label_4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">You will need to add Bluetooth devices before they can be synced.</property>
+ </widget>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="new_device_btn">
+ <property name="label" translatable="yes">Add new device</property>
+ <property name="width_request">150</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">8</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </widget>
</child>
</widget>
- <packing>
- <property name="padding">40</property>
- <property name="position">0</property>
- </packing>
</child>
</widget>
</child>
</child>
</widget>
<packing>
+ <property name="padding">6</property>
<property name="position">0</property>
</packing>
</child>
</child>
</widget>
<widget class="GtkWindow" id="emergency_win">
+ <property name="width_request">1024</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Sync Emergency</property>
<property name="modal">True</property>
<child>
<widget class="GtkLabel" id="emergency_expander_label">
<property name="visible">True</property>
- <property name="label">Affected data: ZYB Contacts, Calendar -- not implemented yet</property>
+ <property name="label">Affected data:</property>
</widget>
<packing>
<property name="type">label_item</property>
<child>
<widget class="GtkHBox" id="hbox19">
<property name="visible">True</property>
+ <property name="spacing">6</property>
<child>
<widget class="GtkButton" id="slow_sync_btn">
- <property name="label" translatable="yes">Slow sync </property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <child>
+ <widget class="GtkLabel" id="slow_sync_btn_label">
+ <property name="visible">True</property>
+ <property name="xpad">16</property>
+ <property name="label" translatable="yes">Slow sync</property>
+ </widget>
+ </child>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label19">
+ <widget class="GtkLabel" id="slow_sync_explanation_label">
<property name="visible">True</property>
<property name="xpad">8</property>
<property name="label" translatable="yes">A slow sync compares items from both sides and tries to merge them.
<property name="visible">True</property>
<child>
<widget class="GtkButton" id="refresh_from_server_btn">
- <property name="label">Delete all your local
-information and replace
-with data from Zyb</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <child>
+ <widget class="GtkLabel" id="refresh_from_server_btn_label">
+ <property name="visible">True</property>
+ <property name="xpad">16</property>
+ <property name="label" translatable="yes">Delete all your local
+information and replace
+with data from Zyb</property>
+ </widget>
+ </child>
</widget>
<packing>
<property name="expand">False</property>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xpad">15</property>
- <property name="label" translatable="yes" comments="text between the two "start from scratch" buttons in emergency view">or</property>
+ <property name="label" translatable="yes" comments="text between the two "start from scratch" buttons in emergency view"><b>or</b></property>
+ <property name="use_markup">True</property>
</widget>
<packing>
<property name="expand">False</property>
</child>
<child>
<widget class="GtkButton" id="refresh_from_client_btn">
- <property name="label">Delete all data on Zyb
-and replace with your
-local information</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <child>
+ <widget class="GtkLabel" id="refresh_from_client_btn_label">
+ <property name="visible">True</property>
+ <property name="xpad">16</property>
+ <property name="label" translatable="yes">Delete all data on Zyb
+and replace with your
+local information</property>
+ </widget>
+ </child>
</widget>
<packing>
<property name="expand">False</property>
</child>
<child>
<widget class="GtkVBox" id="vbox21">
+ <property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
+ <property name="resize_mode">queue</property>
<property name="left_padding">40</property>
- <property name="right_padding">200</property>
+ <property name="right_padding">40</property>
<child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <widget class="GtkVBox" id="vbox22">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">automatic</property>
- <property name="vscrollbar_policy">automatic</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <widget class="GtkLabel" id="label12">
+ <property name="width_request">800</property>
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes" comments="explanation of "Restore backup" function">Backups are made before every time we Sync. Choose a backup to restore. Any changes you have made since then will be lost.</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
- <widget class="GtkViewport" id="backup_viewport">
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
- <property name="resize_mode">queue</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <widget class="GtkTable" id="table1">
+ <widget class="GtkViewport" id="backup_viewport">
<property name="visible">True</property>
- <property name="border_width">3</property>
- <property name="n_rows">10</property>
- <property name="n_columns">2</property>
- <property name="row_spacing">3</property>
- <child>
- <widget class="GtkLabel" id="label59">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing Dec 5th 2009 16:35</property>
- </widget>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label69">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing Dec 5th 2009 13:35</property>
- </widget>
- <packing>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label79">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing Dec 5th 2009 11:35</property>
- </widget>
- <packing>
- <property name="top_attach">4</property>
- <property name="bottom_attach">5</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
+ <property name="resize_mode">queue</property>
<child>
- <widget class="GtkLabel" id="label89">
+ <widget class="GtkTable" id="emergency_backup_table">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing Dec 3rd</property>
- </widget>
- <packing>
- <property name="top_attach">5</property>
- <property name="bottom_attach">6</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label109">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing Dec 1st</property>
- </widget>
- <packing>
- <property name="top_attach">6</property>
- <property name="bottom_attach">7</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label29">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing yesterday</property>
- </widget>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label30">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="ypad">5</property>
- <property name="label">Backup before syncing two hours ago</property>
- </widget>
- <packing>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkButton" id="button1">
- <property name="label">not implemented yet</property>
- <property name="width_request">150</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
+ <property name="n_rows">10</property>
+ <property name="n_columns">2</property>
+ <property name="row_spacing">16</property>
+ <child>
+ <widget class="GtkLabel" id="label59">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing Dec 5th 2009 16:35</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label69">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing Dec 5th 2009 13:35</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label79">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing Dec 5th 2009 11:35</property>
+ </widget>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label89">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing Dec 3rd</property>
+ </widget>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label109">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing Dec 1st</property>
+ </widget>
+ <packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing yesterday</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label30">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label">Backup before syncing two hours ago</property>
+ </widget>
+ <packing>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="label">Restore</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">16</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- <property name="x_padding">16</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
</child>
</widget>
</child>
</widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
</child>
</widget>
</child>
+++ /dev/null
-<?xml version="1.0"?>
-<!-- SYNTHESIS SYNCML CLIENT Version 3.2 Configuration file -->
-
-<sysync_config version="1.0">
-
- <configvar name="logpath" value="$(defout_path)"/>
-
- <!-- this string is output to every session debug logfile to identify the config in use -->
- <configidstring>SyncEvolution client config</configidstring>
-
- <!-- information about maximum supported message and object size (in bytes) -->
- <maxmsgsize/>
- <maxobjsize/>
-
- <!-- information for DevInf -->
- <model/>
- <manufacturer/>
- <hardwareversion/>
- <firmwareversion/>
- <devicetype/>
- <configdate/>
-
- <debug/>
-
- <transport type="xpt">
- <!-- allow HTTP 1.1 kepp-alive (multiple request-answer-exchanges in single TCP connection) -->
- <keepconnection>true</keepconnection>
- </transport>
-
-
- <scripting>
- <looptimeout>5</looptimeout>
-
- <function><![CDATA[
- // create a UID
- string newuid() {
- return "syuid" + NUMFORMAT(RANDOM(1000000),6,"0") + "." + (string)MILLISECONDS(NOW());
- }
- ]]></function>
- <macro name="VCARD_BEFOREWRITE_SCRIPT_EVOLUTION"><![CDATA[
- // a wordaround for cellphone in evolution. for incoming contacts, if there is only one CELL,
- // strip the HOME or WORK flag from it. Evolution then should show it. */
- INTEGER i, wanted, cell_phones;
- i = 0;
- cell_phones = 0;
- while(i < SIZE(TEL_FLAGS)) {
- // 0x10 is the flag of 'cell' type of telephone
- if(TEL_FLAGS[i] & 0x10) {
- cell_phones = cell_phones + 1;
- wanted = i;
- }
- i = i + 1;
- }
- if(cell_phones == 1) {
- TEL_FLAGS[wanted] = 0x10;
- }
-
- // Google sends TYPE=WORK and TYPE=HOME when it means
- // normal VOICE phone numbers. Add that flag when
- // importing into Evolution, because Evolution does not
- // display the numbers without VOICE.
- i = 0;
- while(i < SIZE(TEL_FLAGS)) {
- if(TEL_FLAGS[i] == 1 || TEL_FLAGS[i] == 2) {
- TEL_FLAGS[i] = TEL_FLAGS[i] | 8;
- }
- i = i + 1;
- }
- ]]></macro>
- <macro name="VCALENDAR_20TO10_PRIORITY_CONVERSION"><![CDATA[
- //vCalendar10 has different interpretation from iCalendar20 in 'priority'.
- //see mappings:
- // Category vCalendar1.0 iCalendar2.0
- // undefined 0 0
- // high 1 1 ~ 4
- // normal 2 5
- // low 3 6 ~ bigger
- if(PRIORITY<5 && PRIORITY>0) {
- PRIORITY=1;
- }else if(PRIORITY==5){
- PRIORITY=2;
- }else if(PRIORITY>5){
- PRIORITY=3;
- } // 0 is undefined and remains unchanged
- ]]></macro>
- <macro name="VCALENDAR_10TO20_PRIORITY_CONVERSION"><![CDATA[
- if(PRIORITY==2) {
- PRIORITY=5;
- }else if(PRIORITY==3){
- PRIORITY=7;
- } //others remain unchanged
- ]]></macro>
- <macro name="VCALENDAR10_BEFOREWRITE_SCRIPT"><![CDATA[
- $VCALENDAR_20TO10_PRIORITY_CONVERSION;
- ]]></macro>
- <macro name="VCALENDAR10_AFTERREAD_SCRIPT"><![CDATA[
- $VCALENDAR_10TO20_PRIORITY_CONVERSION;
- ]]></macro>
-
- <macro name="VCARD_INCOMING_NAMECHANGE_SCRIPT"><![CDATA[
- STRING tmp;
- tmp=NORMALIZED(FN);
- if (tmp==EMPTY){
- tmp=N_FIRST;
- if (N_MIDDLE != EMPTY) {
- if (tmp != EMPTY) {
- tmp = tmp + " ";
- }
- tmp = tmp + N_MIDDLE;
- }
- if (N_LAST != EMPTY) {
- if (tmp != EMPTY) {
- tmp = tmp + " ";
- }
- tmp = tmp + N_LAST;
- }
- FN = tmp;
- }
- ]]></macro>
-
- <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
-
- <macro name="VCALENDAR_INCOMING_SCRIPT"><![CDATA[
- STRING MATCHES[];
- STRING CAT,CN,EM;
- INTEGER i;
- // make sure we have all trailing and leading spaces eliminated
- DESCRIPTION=NORMALIZED(DESCRIPTION);
- SUMMARY=NORMALIZED(SUMMARY);
- // make sure that we have a DESCRIPTION
- if (DESCRIPTION==EMPTY) DESCRIPTION=SUMMARY;
- // calendar or todo
- if (ISEVENT) {
- // VEVENT
- // - handle duration cases
- if (ISDURATION(DURATION)) {
- if (DTEND==EMPTY) DTEND = DTSTART + DURATION;
- if (DTSTART==EMPTY) DTSTART = DTEND - DURATION;
- }
- // - detect alldays in vCalendar 1.0 (0:00-0:00 or 23:59 localtime)
- i = ALLDAYCOUNT(DTSTART,DTEND,TRUE);
- if (ITEMDATATYPE()=="vCalendar10" && i>0) {
- // DTSTART and DTEND represent allday event, make them date-only values
- // - convert start to user zone (or floating) so it represents midnight
- DTSTART = CONVERTTOUSERZONE(DTSTART);
- MAKEALLDAY(DTSTART,DTEND,i);
- }
-
- // Make sure that all EXDATE times are in the same timezone as the start
- // time. Some servers send them as UTC, which is all fine and well, but
- // only if the timezone definition doesn't change. Also, libical does not
- // handle such UTC EXDATEs, so let's convert it while the UTC and
- // time zone definition (hopefully) are in sync.
- if (TIMEZONE(DTSTART) != "UTC" && !ISFLOATING(DTSTART)) {
- i = 0;
- timestamp exdate;
- while (i<SIZE(EXDATES)) {
- exdate = EXDATES[i];
- if (!ISDATEONLY(exdate) &&
- (TIMEZONE(exdate) == "UTC" || ISFLOATING(exdate))) {
- // "unfloat" floating time stamps: not sure whether that occcurs
- // in practice, but it looks as wrong as UTC EXDATEs
- EXDATES[i] = CONVERTTOZONE(exdate,DTSTART,TRUE);
- }
- i=i+1;
- }
- }
- // If vcalendar1.0, rrule is not secondly, minutely, or hourly, we strip time information
- // and only reserve date information
- if (ITEMDATATYPE()=="vCalendar10" && RR_FREQ!="h" && RR_FREQ!="m" && RR_FREQ!="s") {
- timestamp exdate;
- i = 0;
- while (i<SIZE(EXDATES)) {
- exdate = EXDATES[i];
- if (!ISDATEONLY(exdate)) {
- EXDATES[i] = DATEONLY(exdate);
- }
- i=i+1;
- }
- }
-
- // - shape attendees (and make sure ATTENDEES[] is assigned even for empty email addresses)
- i=0;
- while(i<SIZE(ATTENDEES) || i<SIZE(ATTENDEE_CNS)) {
- PARSEEMAILSPEC(ATTENDEES[i], CN, EM);
- ATTENDEES[i] = EM; // pure email address
- // in case we have no specific common name, use the one extracted from the email
- // This catches the vCalendar 1.0 case and eventually ill-formed iCalendar 2.0 as well
- if (ATTENDEE_CNS[i]==EMPTY)
- ATTENDEE_CNS[i]=CN;
- // default participation status to needs-action
- if (ATTENDEE_PARTSTATS[i]==EMPTY)
- ATTENDEE_PARTSTATS[i]=1; // 1=needs action
- i=i+1;
- }
- // - shape organizer
- PARSEEMAILSPEC(ORGANIZER, CN, EM);
- ORGANIZER = EM; // pure email address
- if (ORGANIZER_CN==EMPTY)
- ORGANIZER_CN=CN;
- }
- else {
- // VTODO
- // - make sure we have at least a summary
- if (SUMMARY==EMPTY) SUMMARY=DESCRIPTION; // use description if we don't have a summary
- if (SUMMARY==EMPTY) SUMMARY="unnamed"; // set dummy summary if we still don't have one
- // due shaping for non-iCalendar 2.0
- if (ITEMDATATYPE()=="vCalendar10" && ALLDAYCOUNT(DUE,DUE,TRUE,TRUE)>0) {
- DUE = DATEONLY(DUE);
- }
- if (ITEMDATATYPE()=="vCalendar10") {
- $VCALENDAR_10TO20_PRIORITY_CONVERSION;
- }
- }
- // a workaround for funambol: adding 'action' for 'alarm'
- if (ITEMDATATYPE()=="iCalendar20") {
- if (ALARM_TIME!=EMPTY && ALARM_ACTION==EMPTY) {
- ALARM_ACTION = "DISPLAY";
- }
- }
- ]]></macro>
-
- <macro name="VCALENDAR_OUTGOING_SCRIPT"><![CDATA[
- // set UTC time of generation for iCalendar 2.0 DTSTAMP
- DGENERATED = NOW();
- // make sure we have all trailing and leading spaces eliminated
- DESCRIPTION=NORMALIZED(DESCRIPTION);
- SUMMARY=NORMALIZED(SUMMARY);
- if (ISEVENT) {
- // VEVENT
- // - combine attendee email address and common name into single string for vCalendar 1.0
- if (ITEMDATATYPE()=="vCalendar10") {
- i=0;
- while(i<SIZE(ATTENDEES)) {
- ATTENDEES[i] = MAKEEMAILSPEC(ATTENDEE_CNS[i], ATTENDEES[i]);
- i=i+1;
- }
- ORGANIZER = MAKEEMAILSPEC(ORGANIZER_CN, ORGANIZER);
- }
- }
- else {
- // VTODO
- // interal representation is iCalendar20
- if (ITEMDATATYPE()=="vCalendar10") {
- $VCALENDAR_20TO10_PRIORITY_CONVERSION;
- }
- }
- // make sure we have at least a summary
- if (SUMMARY==EMPTY) SUMMARY=SUBSTR(DESCRIPTION,0,32); // derive from description
- if (SUMMARY==EMPTY) SUMMARY="unnamed"; // in case description is empty as well
- // make sure that we have a DESCRIPTION
- if (DESCRIPTION==EMPTY) DESCRIPTION=SUMMARY;
- // do NOT send duration (some servers crash when doing so)
- DURATION = UNASSIGNED;
- // shape alarm
- if (ALARM_TIME!=EMPTY) {
- if (ITEMDATATYPE()=="iCalendar20") {
- if (ALARM_ACTION==EMPTY) ALARM_ACTION = "AUDIO";
- }
- else {
- if (ALARM_MSG==EMPTY) ALARM_MSG="alarm";
- }
- }
- ]]></macro>
-
- </scripting>
-
-
- <datatypes>
-
- <!-- list of internal fields representing vCard data -->
- <fieldlist name="contacts">
- <field name="REV" type="timestamp" compare="never" age="yes"/>
-
- <!-- Name elements -->
- <field name="N_LAST" type="string" compare="always"/>
- <field name="N_FIRST" type="string" compare="always"/>
- <field name="N_MIDDLE" type="string" compare="always"/>
- <field name="N_PREFIX" type="string" compare="conflict"/>
- <field name="N_SUFFIX" type="string" compare="conflict"/>
- <field name="NICKNAME" type="string" compare="conflict"/>
- <field name="TITLE" type="string" compare="conflict" merge="fillempty"/>
-
- <field name="FN" type="string" compare="conflict" merge="fillempty"/>
- <field name="FILE-AS" type="string" compare="conflict" merge="fillempty"/>
-
- <field name="GENDER" type="string" compare="conflict" merge="fillempty"/>
-
- <!-- categories and classification -->
- <field name="CATEGORIES" array="yes" type="string" compare="conflict"/>
-
- <!-- organisation -->
- <field name="ORG_NAME" type="string" compare="slowsync" merge="fillempty"/>
- <field name="ORG_DIVISION" type="string" compare="conflict" merge="fillempty"/>
- <field name="ORG_OFFICE" type="string" compare="conflict" merge="fillempty"/>
- <field name="ORG_TEAM" type="string" compare="conflict" merge="fillempty"/>
- <field name="ROLE" type="string" compare="conflict" merge="fillempty"/>
-
- <!-- birthday and anniversary (not necessarily the same) -->
- <field name="BDAY" type="date" compare="conflict" merge="fillempty"/>
- <field name="ANNIVERSARY" type="date" compare="conflict" merge="fillempty"/>
-
- <!-- telephone numbers -->
- <field name="TEL" array="yes" type="telephone" compare="conflict"/>
- <field name="TEL_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
- <field name="TEL_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
- <field name="TEL_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
- <field name="TEL_SLOT" array="yes" type="integer" compare="never"/> <!-- offset 3 -->
-
- <!-- emails -->
- <field name="EMAIL" array="yes" type="multiline" compare="conflict"/>
- <field name="EMAIL_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
- <field name="EMAIL_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
- <field name="EMAIL_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
- <field name="EMAIL_SLOT" array="yes" type="integer" compare="never"/> <!-- offset 3 -->
-
- <!-- web addresses -->
- <field name="WEB" array="yes" type="string" compare="conflict"/>
- <field name="WEB_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
- <field name="WEB_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
- <field name="WEB_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
-
- <!-- would be nicer to have as part of WEB, but parser/encoder does not support mapping
- with more than one property per field -->
- <field name="CALURI" array="yes" type="string" compare="conflict"/>
- <field name="FBURL" array="yes" type="string" compare="conflict"/>
- <field name="BLOGURL" array="yes" type="string" compare="conflict"/>
- <field name="VIDEOURL" array="yes" type="string" compare="conflict"/>
-
- <!-- related persons: should be turned into array, like WEB and CALURI/FBURL -->
- <field name="MANAGER" type="string" compare="conflict"/>
- <field name="ASSISTANT" type="string" compare="conflict"/>
- <field name="SPOUSE" type="string" compare="conflict"/>
-
- <!-- does this person want HTML mails? Valid values are TRUE/FALSE; a "boolean"
- type would be useful, maybe add that later. -->
- <field name="WANTS_HTML" type="string" compare="conflict"/>
-
- <!-- chat handles: should be turned into one array, like WEB and CALURI/FBURL -->
- <field name="AIM_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="AIM_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="GADUGADU_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="GADUGADU_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="GROUPWISE_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="GROUPWISE_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="ICQ_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="ICQ_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="JABBER_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="JABBER_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="MSN_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="MSN_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="YAHOO_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="YAHOO_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="SKYPE_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="SKYPE_SLOT" array="yes" type="string" compare="conflict"/>
- <field name="SIP_HANDLE" array="yes" type="string" compare="conflict"/>
- <field name="SIP_SLOT" array="yes" type="string" compare="conflict"/>
-
- <!-- home address -->
- <field name="ADR_STREET" array="yes" type="multiline" compare="conflict"/>
- <field name="ADR_ADDTL" array="yes" type="multiline" compare="conflict"/>
- <field name="ADR_STREET_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 (from ADR_STREET_FLAGS) -->
- <field name="ADR_STREET_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
- <field name="ADR_STREET_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
- <field name="ADR_POBOX" array="yes" type="multiline" compare="conflict"/>
- <field name="ADR_CITY" array="yes" type="multiline" compare="conflict"/>
- <field name="ADR_REG" array="yes" type="multiline" compare="conflict"/>
- <field name="ADR_ZIP" array="yes" type="multiline" compare="conflict"/>
- <field name="ADR_COUNTRY" array="yes" type="multiline" compare="conflict"/>
-
- <!-- Note -->
- <field name="NOTE" type="multiline" compare="conflict" merge="lines"/>
-
- <!-- Photo -->
- <field name="PHOTO" type="blob" compare="never" merge="fillempty"/>
- <field name="PHOTO_TYPE" type="integer" compare="never" merge="fillempty"/>
-
- </fieldlist>
-
- <!-- vCard profile -->
- <mimeprofile name="vCard" fieldlist="contacts">
-
- <profile name="VCARD" nummandatory="0"> <!-- we allow records without "N" as Address book can store them -->
- <property name="VERSION">
- <value conversion="version"/>
- </property>
-
- <property onlyformode="standard" name="PRODID" mandatory="no">
- <value conversion="prodid"/>
- </property>
-
- <property name="REV">
- <value field="REV"/>
- </property>
-
- <property name="N" values="5" mandatory="yes"> <!-- Note: makes N parse and generate even if not in remote's CTCap -->
- <value index="0" field="N_LAST"/>
- <value index="1" field="N_FIRST"/>
- <value index="2" field="N_MIDDLE"/>
- <value index="3" field="N_PREFIX"/>
- <value index="4" field="N_SUFFIX"/>
- </property>
-
- <property name="FN">
- <value field="FN"/>
- </property>
-
- <property name="X-EVOLUTION-FILE-AS">
- <value field="FILE-AS"/>
- </property>
-
- <property name="X-GENDER">
- <value field="GENDER"/>
- </property>
-
- <!-- onlyformode="standard": not part of vCard 2.1, but some
- peers (like the Funambol server) accept it anyway in
- vCard 2.1 -->
- <property name="NICKNAME">
- <value field="NICKNAME"/>
- </property>
-
- <property name="TITLE">
- <value field="TITLE"/>
- </property>
-
- <property name="CATEGORIES" values="list" valueseparator="," altvalueseparator=";" > <!-- non-standard, but 1:1 as in vCard 3.0 (NOT like in vCalendar 1.0, where separator is ";") -->
- <value field="CATEGORIES"/>
- <position field="CATEGORIES" repeat="array" increment="1" minshow="0"/>
- </property>
-
- <property name="ORG" values="4">
- <value index="0" field="ORG_NAME"/>
- <value index="1" field="ORG_DIVISION"/>
- <value index="2" field="ORG_OFFICE"/>
- <value index="3" field="ORG_TEAM"/>
- </property>
-
- <property name="ROLE">
- <value field="ROLE"/>
- </property>
-
- <property name="TEL">
- <value field="TEL"/>
- <position field="TEL" repeat="array" increment="1" minshow="1"/>
- <parameter name="TYPE" default="yes" positional="no" show="yes">
- <value field="TEL_FLAGS" conversion="multimix" combine=",">
- <enum name="HOME" value="B0"/>
- <enum name="WORK" value="B1"/>
- <enum mode="ignore" value="B2"/> <!-- OTHER -->
- <enum name="VOICE" value="B3"/>
- <enum name="CELL" value="B4"/>
- <enum name="FAX" value="B5"/>
- <enum name="PAGER" value="B6"/>
- <enum name="PREF" value="B7"/>
- <enum name="CAR" value="B8"/>
- <enum name="X-EVOLUTION-CALLBACK" value="B9"/>
- <enum name="X-EVOLUTION-RADIO" value="B10"/>
- <enum name="X-EVOLUTION-TELEX" value="B11"/>
- <enum name="X-EVOLUTION-TTYTDD" value="B12"/>
-
- <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
- <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
- </value>
- </parameter>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="TEL_SLOT"/>
- </parameter>
- </property>
-
- <property name="EMAIL">
- <value field="EMAIL"/>
- <position field="EMAIL" repeat="array" increment="1" minshow="1"/>
- <parameter name="TYPE" default="yes" positional="no" show="yes">
- <value field="EMAIL_FLAGS" conversion="multimix" combine=",">
- <enum name="HOME" value="B0"/>
- <enum name="WORK" value="B1"/>
- <enum mode="ignore" value="B2"/> <!-- OTHER -->
- <enum name="INTERNET" value="B3"/>
-
- <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
- <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
- </value>
- </parameter>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="EMAIL_SLOT"/>
- </parameter>
- </property>
-
- <property name="URL">
- <value field="WEB"/>
- <position field="WEB" repeat="array" increment="1" minshow="1"/>
- <parameter name="TYPE" default="yes" positional="no" show="yes">
- <value field="WEB_FLAGS" conversion="multimix" combine=",">
- <enum name="HOME" value="B0"/>
- <enum name="WORK" value="B1"/>
- <enum mode="ignore" value="B2"/> <!-- OTHER -->
- <enum name="PREF" value="B3"/>
-
- <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
- <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
- </value>
- </parameter>
- </property>
-
- <property name="CALURI" suppressempty="yes">
- <value field="CALURI" show="yes"/>
- </property>
- <property name="FBURL" suppressempty="yes">
- <value field="FBURL" show="yes"/>
- </property>
- <property name="X-EVOLUTION-BLOG-URL" suppressempty="yes">
- <value field="BLOGURL" show="yes"/>
- </property>
- <property name="X-EVOLUTION-VIDEO-URL" suppressempty="yes">
- <value field="VIDEOURL" show="yes"/>
- </property>
-
- <!-- item for SyncML server: EVOLUTION rule not active,
- both X-EVOLUTION-MANAGER and X-MANAGER are sent.
-
- item from SyncML server: EVOLUTION rule not active,
- both X-EVOLUTION-MANAGER and X-MANAGER are checked,
- but X-EVOLUTION-MANAGER later so that it overwrites
- a value set earlier by X-MANAGER (if any). This is
- a more or less arbitrary priority, chosen because
- servers that know about SyncEvolution (ScheduleWorld,
- Memotoo) use the X-EVOLUTION variant.
-
- item to/from Evolution: EVOLUTION rule is active,
- only X-EVOLUTION-MANAGER is used. -->
- <property name="X-EVOLUTION-MANAGER" suppressempty="yes" delayedparsing="1">
- <value field="MANAGER" show="yes"/>
- </property>
- <property name="X-MANAGER" suppressempty="yes" rule="EVOLUTION"/> <!-- disables the X-MANAGER for EVOLUTION -->
- <property name="X-MANAGER" suppressempty="yes" rule="other">
- <value field="MANAGER" show="yes"/>
- </property>
-
- <property name="X-EVOLUTION-ASSISTANT" suppressempty="yes" delayedparsing="1">
- <value field="ASSISTANT" show="yes"/>
- </property>
- <property name="X-ASSISTANT" suppressempty="yes" rule="EVOLUTION"/>
- <property name="X-ASSISTANT" suppressempty="yes" rule="other">
- <value field="ASSISTANT" show="yes"/>
- </property>
-
- <property name="X-EVOLUTION-SPOUSE" suppressempty="yes" delayedparsing="1">
- <value field="SPOUSE" show="yes"/>
- </property>
- <property name="X-SPOUSE" suppressempty="yes" rule="EVOLUTION"/>
- <property name="X-SPOUSE" suppressempty="yes" rule="other">
- <value field="SPOUSE" show="yes"/>
- </property>
-
- <property name="X-EVOLUTION-ANNIVERSARY" suppressempty="yes" delayedparsing="1">
- <value field="ANNIVERSARY" show="yes"/>
- </property>
- <property name="X-ANNIVERSARY" suppressempty="yes" rule="EVOLUTION"/>
- <property name="X-ANNIVERSARY" suppressempty="yes" rule="other">
- <value field="ANNIVERSARY" show="yes"/>
- </property>
-
- <property name="X-MOZILLA-HTML">
- <value field="WANTS_HTML" show="yes"/>
- </property>
-
- <property name="X-AIM" suppressempty="yes">
- <value field="AIM_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="AIM_SLOT"/>
- </parameter>
- </property>
- <property name="X-GADUGADU" suppressempty="yes">
- <value field="GADUGADU_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="GADUGADU_SLOT"/>
- </parameter>
- </property>
- <property name="X-GROUPWISE" suppressempty="yes">
- <value field="GROUPWISE_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="GROUPWISE_SLOT"/>
- </parameter>
- </property>
- <property name="X-ICQ" suppressempty="yes">
- <value field="ICQ_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="ICQ_SLOT"/>
- </parameter>
- </property>
- <property name="X-JABBER" suppressempty="yes">
- <value field="JABBER_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="JABBER_SLOT"/>
- </parameter>
- </property>
- <property name="X-MSN" suppressempty="yes">
- <value field="MSN_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="MSN_SLOT"/>
- </parameter>
- </property>
- <property name="X-YAHOO" suppressempty="yes">
- <value field="YAHOO_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="YAHOO_SLOT"/>
- </parameter>
- </property>
-
- <property name="X-SKYPE" suppressempty="yes">
- <value field="SKYPE_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="SKYPE_SLOT"/>
- </parameter>
- </property>
-
- <property name="X-SIP" suppressempty="yes">
- <value field="SIP_HANDLE"/>
- <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
- <value field="SIP_SLOT"/>
- </parameter>
- </property>
-
- <property name="ADR" values="7">
- <value index="0" field="ADR_POBOX"/>
- <value index="1" field="ADR_ADDTL"/>
- <value index="2" field="ADR_STREET"/>
- <value index="3" field="ADR_CITY"/>
- <value index="4" field="ADR_REG"/>
- <value index="5" field="ADR_ZIP"/>
- <value index="6" field="ADR_COUNTRY"/>
- <position field="ADR_POBOX" repeat="array" increment="1" minshow="1"/>
- <parameter name="TYPE" default="yes" positional="no" show="yes">
- <value field="ADR_STREET_FLAGS" conversion="multimix" combine=",">
- <enum name="HOME" value="B0"/>
- <enum name="WORK" value="B1"/>
- <enum mode="ignore" value="B2"/> <!-- OTHER -->
-
- <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
- <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
- </value>
- </parameter>
- </property>
-
- <property name="BDAY">
- <value field="BDAY"/>
- </property>
-
- <property name="NOTE" filter="no">
- <value field="NOTE"/>
- </property>
-
- <property name="PHOTO" filter="no">
- <value field="PHOTO" conversion="BLOB_B64"/>
- <parameter name="TYPE" default="no" show="yes">
- <value field="PHOTO_TYPE">
- <enum name="JPEG" value="0"/>
- </value>
- </parameter>
- </property>
-
- </profile>
- </mimeprofile>
-
- <!-- vCard 2.1 datatype, using vCard profile defined above -->
- <datatype name="vCard21" basetype="vcard">
- <version>2.1</version>
- <use mimeprofile="vCard"/>
- <incomingscript><![CDATA[
- $VCARD_INCOMING_NAMECHANGE_SCRIPT
- ]]></incomingscript>
- </datatype>
-
- <!-- vCard 3.0 datatype, using vCard profile defined above -->
- <datatype name="vCard30" basetype="vcard">
- <version>3.0</version>
- <use mimeprofile="vCard"/>
- <incomingscript><![CDATA[
- $VCARD_INCOMING_NAMECHANGE_SCRIPT
- ]]></incomingscript>
- </datatype>
-
-
- <!-- common field list for events and todos (both represented by vCalendar/iCalendar) -->
- <fieldlist name="calendar">
- <field name="ISEVENT" type="integer" compare="always"/>
-
- <field name="DMODIFIED" type="timestamp" compare="never" age="yes"/>
- <field name="DCREATED" type="timestamp" compare="never"/>
-
- <field name="DGENERATED" type="timestamp" compare="never"/>
-
- <field name="UID" type="string" compare="never"/>
-
- <field name="CATEGORIES" array="yes" type="string" compare="conflict" merge="fillempty"/>
- <field name="CLASS" type="integer" compare="conflict" merge="fillempty"/>
- <field name="TRANSP" type="integer" compare="conflict" merge="fillempty"/>
-
- <field name="SUMMARY" type="multiline" compare="always"/>
- <field name="DESCRIPTION" type="multiline" compare="slowsync" merge="lines"/>
- <field name="LOCATION" type="multiline" compare="slowsync" merge="lines"/>
- <field name="URL" type="url" compare="conflict"/>
-
- <!-- recurrence rule block, fields must be in that order, including
- DTSTART as last field !! -->
- <field name="RR_FREQ" type="string" compare="conflict"/>
- <field name="RR_INTERVAL" type="integer" compare="conflict"/>
- <field name="RR_FMASK" type="integer" compare="conflict"/>
- <field name="RR_LMASK" type="integer" compare="conflict"/>
- <field name="RR_END" type="timestamp" compare="conflict"/>
-
- <!-- Note: DTSTART/DTEND are compared in the <comparescript>,
- therefore compare is set no "never" here -->
- <field name="DTSTART" type="timestamp" compare="never"/>
- <field name="DTEND" type="timestamp" compare="never"/>
- <field name="DURATION" type="timestamp" compare="never"/>
- <field name="COMPLETED" type="timestamp" compare="never"/>
- <field name="DUE" type="timestamp" compare="never"/>
-
- <field name="GEO_LAT" type="string" compare="never"/>
- <field name="GEO_LONG" type="string" compare="never"/>
-
- <field name="PRIORITY" type="integer" compare="conflict"/>
- <field name="STATUS" type="integer" compare="conflict" merge="fillempty"/>
- <field name="PERCENT_COMPLETE" type="integer" compare="conflict"/>
-
- <field name="ALARM_TIME" type="timestamp" compare="conflict"/>
- <field name="ALARM_SNOOZE" type="string" compare="conflict"/>
- <field name="ALARM_REPEAT" type="string" compare="conflict"/>
- <field name="ALARM_MSG" type="string" compare="conflict"/>
- <field name="ALARM_ACTION" type="string" compare="conflict"/>
- <field name="ALARM_REL" type="integer" compare="never"/>
- <field name="ALARM_UID" type="string" compare="conflict"/>
-
- <!-- non-standard -->
- <field name="PARENT_UID" type="string" compare="never"/>
-
- <!-- for events -->
- <field name="EXDATES" array="yes" type="timestamp" compare="never"/>
-
- <field name="ORIGSTART" array="no" type="timestamp" compare="never"/>
- <field name="SEQNO" array="no" type="integer" compare="never"/>
-
- <field name="ATTENDEES" array="yes" type="string" compare="never"/>
- <field name="ATTENDEE_CNS" array="yes" type="string" compare="never"/>
- <field name="ATTENDEE_PARTSTATS" array="yes" type="integer" compare="never"/>
- <field name="ATTENDEE_ROLE" array="yes" type="integer" compare="never"/>
- <field name="ATTENDEE_RSVP" array="yes" type="integer" compare="never"/>
- <field name="ATTENDEE_LANG" array="yes" type="string" compare="never"/>
- <field name="ATTENDEE_CUTYPE" array="yes" type="integer" compare="never"/>
- <field name="ORGANIZER" array="no" type="string" compare="never"/>
- <field name="ORGANIZER_CN" array="no" type="string" compare="never"/>
-
- </fieldlist>
-
-
- <!-- vCalendar with VTODO and VEVENT variants -->
- <mimeprofile name="vCalendar" fieldlist="calendar">
-
- <vtimezonegenmode>current</vtimezonegenmode>
- <tzidgenmode>olson</tzidgenmode>
-
- <profile name="VCALENDAR" nummandatory="1">
-
- <property name="VERSION" mandatory="yes">
- <value conversion="version"/>
- </property>
-
- <property onlyformode="standard" name="PRODID" mandatory="no">
- <value conversion="prodid"/>
- </property>
-
- <property onlyformode="old" name="TZ" filter="false" suppressempty="yes">
- <value field="DTSTART" conversion="tz"/>
- </property>
-
- <property onlyformode="old" name="DAYLIGHT" mode="daylight" filter="false" suppressempty="yes">
- <value field="DTSTART" conversion="daylight"/>
- </property>
-
- <property name="GEO" values="2" suppressempty="yes" onlyformode="old" valueseparator=",">
- <!-- LON,LAT in vCalendar 1.0 -->
- <value index="0" field="GEO_LAT"/>
- <value index="1" field="GEO_LONG"/>
- </property>
-
- <subprofile onlyformode="standard" name="VTIMEZONE" mode="vtimezones"/>
-
- <!-- sub-profile for todoz -->
- <subprofile name="VTODO" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="0">
-
- <property name="LAST-MODIFIED" suppressempty="yes">
- <value field="DMODIFIED"/>
- </property>
-
- <property name="DTSTAMP" suppressempty="yes" onlyformode="standard">
- <value field="DGENERATED"/>
- </property>
-
- <property name="DCREATED" suppressempty="yes" onlyformode="old">
- <value field="DCREATED"/>
- </property>
- <property name="CREATED" suppressempty="yes" onlyformode="standard">
- <value field="DCREATED"/>
- </property>
-
- <property name="UID" suppressempty="yes">
- <value field="UID"/>
- </property>
-
- <property name="SEQUENCE" suppressempty="yes">
- <value field="SEQNO"/>
- </property>
-
- <property name="GEO" values="2" suppressempty="yes" onlyformode="standard" valueseparator=";">
- <!-- LAT;LON in iCalendar 2.0 -->
- <value index="0" field="GEO_LONG"/>
- <value index="1" field="GEO_LAT"/>
- </property>
-
- <property onlyformode="standard" name="CATEGORIES" values="list" valueseparator="," suppressempty="yes">
- <value field="CATEGORIES" />
- <position field="CATEGORIES" repeat="array" minshow="0"/>
- </property>
-
- <property onlyformode="old" name="CATEGORIES" values="list" valueseparator=";" altvalueseparator="," suppressempty="yes">
- <value field="CATEGORIES" />
- <position field="CATEGORIES" repeat="array" minshow="0"/>
- </property>
-
- <property name="CLASS" suppressempty="yes">
- <value field="CLASS">
- <enum name="PUBLIC" value="0"/>
- <enum name="PRIVATE" value="1"/>
- <enum name="CONFIDENTIAL" value="2"/>
- </value>
- </property>
-
- <property name="SUMMARY" mandatory="yes">
- <value field="SUMMARY"/>
- </property>
-
- <!-- DESCRIPTION is an optional property and libical does not like
- empty properties, so suppress it here. However, in the scripts
- we ensure that the DESCRIPTION field should never be empty. -->
- <property name="DESCRIPTION" suppressempty="yes" mandatory="no">
- <value field="DESCRIPTION"/>
- </property>
-
- <property name="LOCATION" suppressempty="yes" mandatory="no">
- <value field="LOCATION"/>
- </property>
-
- <property name="URL" suppressempty="yes" mandatory="no">
- <value field="URL"/>
- </property>
-
- <property name="DTSTART" suppressempty="yes" delayedparsing="1">
- <value field="DTSTART" conversion="autodate"/>
- <parameter onlyformode="standard" name="TZID" default="no" show="yes">
- <value field="DTSTART" conversion="TZID"/>
- </parameter>
- <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
- <value field="DTSTART" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <property name="COMPLETED" suppressempty="yes" delayedparsing="1">
- <value field="COMPLETED" conversion="autoenddate"/>
- <parameter onlyformode="standard" name="TZID" default="no" show="yes">
- <value field="COMPLETED" conversion="TZID"/>
- </parameter>
- <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
- <value field="COMPLETED" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <property name="DUE" suppressempty="yes" delayedparsing="1">
- <value field="DUE" conversion="autodate"/>
- <parameter onlyformode="standard" name="TZID" default="no" show="yes">
- <value field="DUE" conversion="TZID"/>
- </parameter>
- <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
- <value field="DUE" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <property name="PRIORITY" suppressempty="yes">
- <value field="PRIORITY"/>
- </property>
-
- <property name="STATUS" onlyformode="standard" suppressempty="yes">
- <value field="STATUS" conversion="emptyonly">
- <enum name="COMPLETED" value="0"/>
- <enum name="NEEDS-ACTION" value="1"/>
- <enum name="IN-PROCESS" value="2"/>
- <enum name="CANCELLED" value="3"/>
- <enum name="ACCEPTED" value="4"/>
- <enum name="TENTATIVE" value="5"/>
- <enum name="DELEGATED" value="6"/>
- <enum name="DECLINED" value="7"/>
- <enum name="SENT" value="8"/>
- <enum name="CONFIRMED" value="9"/>
- <enum name="DRAFT" value="10"/>
- <enum name="FINAL" value="11"/>
- </value>
- </property>
-
- <property name="STATUS" onlyformode="old" suppressempty="yes">
- <value field="STATUS" conversion="emptyonly">
- <enum name="COMPLETED" value="0"/>
- <enum name="NEEDS ACTION" value="1"/>
- <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
- <enum name="IN PROCESS" value="2"/>
- <enum name="CANCELLED" value="3"/>
- <enum name="ACCEPTED" value="4"/>
- <enum name="TENTATIVE" value="5"/>
- <enum name="DELEGATED" value="6"/>
- <enum name="DECLINED" value="7"/>
- <enum name="SENT" value="8"/>
- <enum name="CONFIRMED" value="9"/>
- <enum name="DRAFT" value="10"/>
- <enum name="FINAL" value="11"/>
- </value>
- </property>
-
- <property name="PERCENT-COMPLETE" onlyformode="standard" suppressempty="yes">
- <value field="PERCENT_COMPLETE"/>
- </property>
-
- <!-- AALARM and DALARM both use the same fields -->
- <property name="AALARM" onlyformode="old" values="4" suppressempty="yes">
- <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
- <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
- <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
- <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
- </property>
- <property name="DALARM" onlyformode="old" values="4" suppressempty="yes">
- <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
- <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
- <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
- <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
- </property>
-
- <subprofile onlyformode="standard" name="VALARM" nummandatory="1" field="ALARM_TIME">
- <property name="TRIGGER" suppressempty="no" mandatory="yes">
- <value field="ALARM_TIME"/>
- <parameter name="VALUE" default="no" show="yes">
- <value field="ALARM_TIME" conversion="FULLVALUETYPE"/>
- </parameter>
- <parameter name="RELATED" default="no" show="yes">
- <value field="ALARM_REL">
- <enum mode="ignore" value="0"/>
- <enum name="START" value="1"/>
- <enum name="END" value="2"/>
- </value>
- </parameter>
- </property>
- <property name="ACTION" suppressempty="yes" mandatory="yes">
- <value field="ALARM_ACTION"/>
- </property>
- <property name="DESCRIPTION" suppressempty="yes">
- <value field="ALARM_MSG"/>
- </property>
- <property name="REPEAT" suppressempty="yes">
- <value field="ALARM_REPEAT"/>
- </property>
- <property name="X-EVOLUTION-ALARM-UID" suppressempty="yes">
- <value field="ALARM_UID"/>
- </property>
- </subprofile>
-
- <property onlyformode="old" name="RELATED-TO" suppressempty="yes">
- <value field="PARENT_UID"/>
- </property>
-
- <property onlyformode="standard" name="RELATED-TO" suppressempty="yes">
- <value field="PARENT_UID"/>
- <parameter onlyformode="standard" name="RELTYPE" default="no" positional="yes" show="yes">
- <value>
- <enum name="PARENT"/>
- <enum mode="defaultvalue" name="other"/>
- </value>
- <position hasnot="other" shows="PARENT" field="PARENT_UID"/>
- </parameter>
- </property>
-
- </subprofile>
-
- <!-- sub-profile for event -->
- <subprofile name="VEVENT" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="1">
-
- <property name="STATUS" suppressempty="yes" onlyformode="old">
- <value field="STATUS" conversion="emptyonly">
- <enum name="COMPLETED" value="0"/>
- <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
- <enum name="NEEDS ACTION" value="1"/>
- <enum name="CANCELLED" value="3"/>
- <enum name="ACCEPTED" value="4"/>
- <enum name="TENTATIVE" value="5"/>
- <enum name="DELEGATED" value="6"/>
- <enum name="DECLINED" value="7"/>
- <enum name="SENT" value="8"/>
- <enum name="CONFIRMED" value="9"/>
- <enum name="FINAL" value="11"/>
- </value>
- </property>
-
- <property name="STATUS" suppressempty="yes" onlyformode="standard">
- <value field="STATUS" conversion="emptyonly">
- <enum name="CANCELLED" value="3"/>
- <enum name="TENTATIVE" value="5"/>
- <enum name="CONFIRMED" value="9"/>
- </value>
- </property>
-
- <property name="LAST-MODIFIED" suppressempty="yes">
- <value field="DMODIFIED"/>
- </property>
-
- <property name="DTSTAMP" suppressempty="yes" onlyformode="standard">
- <value field="DGENERATED"/>
- </property>
-
- <property name="DCREATED" suppressempty="yes" onlyformode="old">
- <value field="DCREATED"/>
- </property>
- <property name="CREATED" suppressempty="yes" onlyformode="standard">
- <value field="DCREATED"/>
- </property>
-
-
- <property name="UID" suppressempty="yes">
- <value field="UID"/>
- </property>
-
- <property name="SEQUENCE" suppressempty="yes">
- <value field="SEQNO"/>
- </property>
-
- <property name="GEO" values="2" suppressempty="yes" onlyformode="standard" valueseparator=";">
- <!-- LAT;LON in iCalendar 2.0 -->
- <value index="0" field="GEO_LONG"/>
- <value index="1" field="GEO_LAT"/>
- </property>
-
- <property onlyformode="standard" name="CATEGORIES" values="list" valueseparator="," suppressempty="yes">
- <value field="CATEGORIES" />
- <position field="CATEGORIES" repeat="array" minshow="0"/>
- </property>
-
- <property onlyformode="old" name="CATEGORIES" values="list" valueseparator=";" altvalueseparator="," suppressempty="yes">
- <value field="CATEGORIES" />
- <position field="CATEGORIES" repeat="array" minshow="0"/>
- </property>
-
- <property name="CLASS" suppressempty="yes">
- <value field="CLASS">
- <enum name="PUBLIC" value="0"/>
- <enum name="PRIVATE" value="1"/>
- <enum name="CONFIDENTIAL" value="2"/>
- </value>
- </property>
-
-
- <property name="TRANSP" suppressempty="yes" onlyformode="standard">
- <value field="TRANSP">
- <enum name="OPAQUE" value="0"/>
- <enum name="TRANSPARENT" value="1"/>
- <enum name="TENTATIVE" value="2"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->
- <enum name="OUT_OF_OFFICE" value="3"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->
- <enum mode="defaultvalue" value="0"/>
- </value>
- </property>
- <property name="TRANSP" suppressempty="yes" onlyformode="old">
- <value field="TRANSP"/> <!-- directly numeric in vCalendar 1.0 -->
- </property>
-
-
- <property name="PRIORITY" suppressempty="yes">
- <value field="PRIORITY"/>
- </property>
-
- <property name="SUMMARY" mandatory="yes">
- <value field="SUMMARY"/>
- </property>
-
- <!-- DESCRIPTION is an optional property and libical does not like
- empty properties, so suppress it here. However, in the scripts
- we ensure that the DESCRIPTION field should never be empty. -->
- <property name="DESCRIPTION" suppressempty="yes" mandatory="no">
- <value field="DESCRIPTION"/>
- </property>
-
- <property name="LOCATION" suppressempty="yes" mandatory="no">
- <value field="LOCATION"/>
- </property>
-
- <property name="DTSTART" suppressempty="yes" delayedparsing="1">
- <value field="DTSTART" conversion="autodate"/>
- <parameter onlyformode="standard" name="TZID" default="no" show="yes">
- <value field="DTSTART" conversion="TZID"/>
- </parameter>
- <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
- <value field="DTSTART" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <!-- recurrence rule (with delayed parsing, as it is dependent on DTSTART) -->
- <property name="RRULE" suppressempty="yes" delayedparsing="2">
- <!-- Note: RR_FREQ is the beginning of a block of fields
- suitable for the "rrule" conversion mode -->
- <value field="RR_FREQ" conversion="rrule"/>
- </property>
-
- <!-- Symbian uses this, so it might make the client work with symbian-prepared servers better -->
- <property name="X-RECURRENCE-ID" suppressempty="yes" onlyformode="old">
- <value field="ORIGSTART" conversion="autodate"/>
- </property>
-
- <property name="RECURRENCE-ID" suppressempty="yes" onlyformode="standard" delayedparsing="1">
- <value field="ORIGSTART" conversion="autodate"/>
- <parameter name="TZID" default="no" show="yes">
- <value field="ORIGSTART" conversion="TZID"/>
- </parameter>
- <parameter name="VALUE" default="no" show="yes">
- <value field="ORIGSTART" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <!-- ScheduleWorld has a problem (bugzilla.moblin.org #2226)
- with the EXDATE:value1,value2 format (correct in iCalendar 2.0):
- as a workaround, accept all valid formats plus ; but
- generate separate properties with one value each. -->
- <property name="EXDATE" values="expandedlist" suppressempty="yes" onlyformode="standard" delayedparsing="1" valueseparator="," altvalueseparator=";">
- <value field="EXDATES"/>
- <position field="EXDATES" repeat="array" increment="1" minshow="0"/>
- <parameter name="TZID" default="no" show="yes">
- <value field="EXDATES" conversion="TZID"/>
- </parameter>
- </property>
-
- <property name="EXDATE" values="list" suppressempty="yes" onlyformode="old" delayedparsing="1" valueseparator=";" altvalueseparator=",">
- <value field="EXDATES"/>
- <position field="EXDATES" repeat="array" increment="1" minshow="0"/>
- </property>
-
-
- <property name="DTEND" suppressempty="yes" delayedparsing="1">
- <value field="DTEND" conversion="autoenddate"/>
- <parameter onlyformode="standard" name="TZID" default="no" show="yes">
- <value field="DTEND" conversion="TZID"/>
- </parameter>
- <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
- <value field="DTEND" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <property name="DURATION" suppressempty="yes" delayedparsing="1" onlyformode="standard">
- <value field="DURATION"/>
- <parameter onlyformode="standard" name="VALUE" default="no" show="no">
- <value field="DURATION" conversion="VALUETYPE"/>
- </parameter>
- </property>
-
- <property name="ATTENDEE" suppressempty="yes" onlyformode="old">
- <value field="ATTENDEES"/>
- <parameter name="ROLE" default="no" positional="yes" show="yes">
- <value>
- <enum name="ORGANIZER"/>
- </value>
- <position has="ORGANIZER" field="ORGANIZER" overwriteempty="yes"/>
- <position hasnot="ORGANIZER" field="ATTENDEES" repeat="array" increment="1" overwriteempty="yes"/>
- </parameter>
- <parameter name="STATUS" default="no" show="yes">
- <value field="ATTENDEE_PARTSTATS">
- <enum name="NEEDS ACTION" value="1"/>
- <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
- <enum name="ACCEPTED" value="4"/>
- <enum name="DECLINED" value="7"/>
- <enum name="TENTATIVE" value="5"/>
- <enum name="DELEGATED" value="6"/>
- </value>
- </parameter>
- </property>
-
- <property name="ATTENDEE" suppressempty="yes" onlyformode="standard">
- <value field="ATTENDEES" conversion="mailto"/>
- <position field="ATTENDEES" repeat="array" increment="1" minshow="0"/>
- <parameter name="CN" default="no" show="yes" shownonempty="yes">
- <value field="ATTENDEE_CNS"/>
- </parameter>
- <parameter name="PARTSTAT" default="no" show="yes">
- <value field="ATTENDEE_PARTSTATS">
- <enum name="NEEDS-ACTION" value="1"/>
- <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
- <enum name="ACCEPTED" value="4"/>
- <enum name="DECLINED" value="7"/>
- <enum name="TENTATIVE" value="5"/>
- <enum name="DELEGATED" value="6"/>
- </value>
- </parameter>
- <parameter name="ROLE" default="no" show="yes">
- <value field="ATTENDEE_ROLE">
- <enum name="CHAIR" value="1"/>
- <enum name="REQ-PARTICIPANT" value="2"/>
- <enum name="OPT-PARTICIPANT" value="3"/>
- <enum name="NON-PARTICIPANT" value="4"/>
- </value>
- </parameter>
- <parameter name="RSVP" default="no" show="yes">
- <value field="ATTENDEE_RSVP">
- <enum name="TRUE" value="1"/>
- <enum name="FALSE" value="0"/>
- </value>
- </parameter>
- <parameter name="LANGUAGE" show="yes">
- <value field="ATTENDEE_LANG"/>
- </parameter>
- <parameter name="CUTYPE" default="no" show="yes">
- <value field="ATTENDEE_CUTYPE">
- <enum name="INDIVIDUAL" value="1"/>
- <enum name="GROUP" value="2"/>
- <enum name="RESOURCE" value="3"/>
- <enum name="ROOM" value="4"/>
- <enum name="UNKNOWN" value="5"/>
- </value>
- </parameter>
- </property>
-
- <property name="ORGANIZER" suppressempty="yes" onlyformode="standard">
- <value field="ORGANIZER" conversion="mailto"/>
- <parameter name="CN" default="no" show="yes">
- <value field="ORGANIZER_CN"/>
- </parameter>
- </property>
-
-
- <!-- AALARM and DALARM both use the same fields -->
- <property name="AALARM" onlyformode="old" values="4" suppressempty="yes">
- <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
- <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
- <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
- <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
- </property>
- <property name="DALARM" onlyformode="old" values="4" suppressempty="yes">
- <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
- <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
- <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
- <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
- </property>
-
- <subprofile onlyformode="standard" name="VALARM" nummandatory="1" field="ALARM_TIME">
- <property name="TRIGGER" suppressempty="no" mandatory="yes">
- <value field="ALARM_TIME"/>
- <parameter name="VALUE" default="no" show="yes">
- <value field="ALARM_TIME" conversion="FULLVALUETYPE"/>
- </parameter>
- <parameter name="RELATED" default="no" show="yes">
- <value field="ALARM_REL">
- <enum mode="ignore" value="0"/>
- <enum name="START" value="1"/>
- <enum name="END" value="2"/>
- </value>
- </parameter>
- </property>
- <property name="ACTION" suppressempty="yes" mandatory="yes">
- <value field="ALARM_ACTION"/>
- </property>
- <property name="DESCRIPTION" suppressempty="yes">
- <value field="ALARM_MSG"/>
- </property>
- <property name="REPEAT" suppressempty="yes">
- <value field="ALARM_REPEAT"/>
- </property>
- <property name="X-EVOLUTION-ALARM-UID" suppressempty="yes">
- <value field="ALARM_UID"/>
- </property>
- </subprofile>
-
- </subprofile>
-
- </profile>
- </mimeprofile>
-
-
- <!-- vCalendar 1.0 datatype, using vCalendar profile defined above -->
- <datatype name="vCalendar10" basetype="vcalendar">
- <version>1.0</version>
- <use mimeprofile="vCalendar"/>
-
- <incomingscript><![CDATA[
- $VCALENDAR_INCOMING_SCRIPT
- ]]></incomingscript>
-
- <outgoingscript><![CDATA[
- $VCALENDAR_OUTGOING_SCRIPT
- ]]></outgoingscript>
-
- </datatype>
-
-
- <!-- iCalendar 2.0 datatype, using vCalendar profile defined above -->
- <datatype name="iCalendar20" basetype="vcalendar">
- <version>2.0</version>
- <use mimeprofile="vCalendar"/>
-
- <incomingscript><![CDATA[
- $VCALENDAR_INCOMING_SCRIPT
- ]]></incomingscript>
-
-
- <outgoingscript><![CDATA[
- $VCALENDAR_OUTGOING_SCRIPT
- ]]></outgoingscript>
-
- </datatype>
-
-
- <!-- list of internal fields representing plain text note data -->
- <fieldlist name="Note">
- <field name="SYNCLVL" type="integer" compare="never"/>
- <field name="SUBJECT" type="multiline" compare="always"/>
- <field name="TEXT" type="multiline" compare="conflict" merge="lines"/>
- </fieldlist>
-
- <textprofile name="Note" fieldlist="Note">
- <linemap field="SUBJECT">
- <numlines>1</numlines>
- <inheader>false</inheader>
- <allowempty>true</allowempty>
- <filterkeyword>SUBJECT</filterkeyword>
- </linemap>
- <linemap field="TEXT">
- <numlines>0</numlines>
- <inheader>false</inheader>
- <allowempty>true</allowempty>
- </linemap>
- </textprofile>
-
- <datatype name="note10" basetype="text">
- <use profile="Note"/>
- <typestring>text/plain</typestring>
- <versionstring>1.0</versionstring>
- </datatype>
-
- <datatype name="note11" basetype="text">
- <use profile="Note"/>
- <typestring>text/plain</typestring>
- <versionstring>1.1</versionstring>
- </datatype>
-
-
- <!-- list of internal fields representing vBookmark data -->
- <fieldlist name="bookmarks">
- <field name="REV" type="timestamp" compare="never" age="yes"/>
- <field name="SYNCLVL" type="integer" compare="never"/>
-
- <!-- Name -->
- <field name="TITLE" type="string" compare="always"/>
-
- <!-- categories and classification -->
- <field name="CATEGORIES" type="string" compare="conflict" merge="fillempty"/>
- <field name="CLASS" type="string" compare="conflict" merge="fillempty"/>
-
- <!-- web addresses -->
- <field name="URL" type="url" compare="slowsync" merge="fillempty"/>
-
- <!-- Note -->
- <field name="NOTE" type="multiline" compare="conflict" merge="lines"/>
-
- </fieldlist>
-
- <!-- vBookmark profile -->
- <mimeprofile name="vBookmark" fieldlist="bookmarks">
-
- <profile name="VBKM" nummandatory="0">
- <property name="VERSION">
- <value conversion="version"/>
- </property>
-
- <property name="X-LAST-MODIFIED">
- <value field="REV"/>
- </property>
-
- <property name="TITLE">
- <value field="TITLE"/>
- </property>
-
- <property name="URL">
- <value field="URL"/>
- </property>
-
- <!-- non-standard properties -->
-
- <property name="CATEGORIES">
- <value field="CATEGORIES"/>
- </property>
-
- <property name="CLASS" suppressempty="yes">
- <value field="CLASS"/>
- </property>
-
- <property name="NOTE" filter="no">
- <value field="NOTE"/>
- </property>
-
- </profile>
- </mimeprofile>
-
- <!-- vBookmark datatype, using vBookmark profile defined above -->
- <datatype name="vBookmark10" basetype="mimedir">
- <typestring>text/x-vbookmark</typestring>
- <versionstring>1.0</versionstring>
- <use profile="vBookmark"/>
- </datatype>
-
- <fieldlists/>
- <profiles/>
- <datatypes/>
- </datatypes>
-
- <clientorserver/>
-
- <client type="plugin">
- <remoterule name="ZYB">
- <manufacturer>ZYB</manufacturer>
- <model>ZYB</model>
- <!-- information to disable anchors checking -->
- <lenientmode>yes</lenientmode>
- </remoterule>
- </client>
-
-</sysync_config>
class Connection;
class Client;
class DBusTransportAgent;
+class DBusUserInterface;
+class DBusServer;
class DBusSyncException : public DBusCXXException, public Exception
{
public:
const std::string m_configName;
- ReadOperations(const std::string &config_name);
+ DBusServer &m_server;
+
+ ReadOperations(const std::string &config_name, DBusServer &server);
/** the double dictionary used to represent configurations */
typedef std::map< std::string, StringMap > Config_t;
typedef SyncSource::Databases SourceDatabases_t;
/** implementation of D-Bus GetConfigs() */
- static void getConfigs(bool getTemplates, std::vector<std::string> &configNames);
+ void getConfigs(bool getTemplates, std::vector<std::string> &configNames);
/** implementation of D-Bus GetConfig() for m_configName as server configuration */
void getConfig(bool getTemplate,
virtual bool setFilters(SyncConfig &config) { return false; }
/** utility method which constructs a SyncConfig which references a local configuration (never a template) */
- boost::shared_ptr<SyncConfig> getLocalConfig(const std::string &configName);
+ boost::shared_ptr<DBusUserInterface> getLocalConfig(const std::string &configName);
};
/**
class InfoReq;
/**
+ * Query bluetooth devices from org.bluez
+ * The basic workflow is:
+ * 1) get default adapter from bluez by calling 'DefaultAdapter' method of org.bluez.Manager
+ * 2) get all devices of the adapter by calling 'ListDevices' method of org.bluez.Adapter
+ * 3) iterate all devices and get properties for each one by calling 'GetProperties' method of org.bluez.Device.
+ * Then check its UUIDs whether it contains sync services and put it in the sync device list if it is
+ *
+ * To track changes of devices dynamically, here also listen signals from bluez:
+ * org.bluez.Manager - DefaultAdapterChanged: default adapter is changed and thus have to get its devices
+ * and update sync device list
+ * org.bluez.Adapter - DeviceCreated, DeviceRemoved: device is created or removed and device list is updated
+ * org.bluez.Device - PropertyChanged: property is changed and device information is changed and tracked
+ *
+ * This class is to manage querying bluetooth devices from org.bluez. Also
+ * it acts a proxy to org.bluez.Manager.
+ */
+class BluezManager : public DBusRemoteObject {
+public:
+ BluezManager(DBusServer &server);
+
+ virtual const char *getDestination() const {return "org.bluez";}
+ virtual const char *getPath() const {return "/";}
+ virtual const char *getInterface() const {return "org.bluez.Manager";}
+ virtual DBusConnection *getConnection() const {return m_bluezConn.get();}
+ bool isDone() { return m_done; }
+
+private:
+ class BluezDevice;
+
+ /**
+ * This class acts a proxy to org.bluez.Adapter.
+ * Call methods of org.bluez.Adapter and listen signals from it
+ * to get devices list and track its changes
+ */
+ class BluezAdapter: public DBusRemoteObject
+ {
+ public:
+ BluezAdapter (BluezManager &manager, const string &path);
+
+ virtual const char *getDestination() const {return "org.bluez";}
+ virtual const char *getPath() const {return m_path.c_str();}
+ virtual const char *getInterface() const {return "org.bluez.Adapter";}
+ virtual DBusConnection *getConnection() const {return m_manager.getConnection();}
+ void checkDone(bool forceDone = false)
+ {
+ if(forceDone || m_devReplies >= m_devNo) {
+ m_devReplies = m_devNo = 0;
+ m_manager.setDone(true);
+ } else {
+ m_manager.setDone(false);
+ }
+ }
+
+ std::vector<boost::shared_ptr<BluezDevice> >& getDevices() { return m_devices; }
+
+ private:
+ /** callback of 'ListDevices' signal. Used to get all available devices of the adapter */
+ void listDevicesCb(const std::vector<DBusObject_t> &devices, const string &error);
+
+ /** callback of 'DeviceRemoved' signal. Used to track a device is removed */
+ void deviceRemoved(const DBusObject_t &object);
+
+ /** callback of 'DeviceCreated' signal. Used to track a new device is created */
+ void deviceCreated(const DBusObject_t &object);
+
+ BluezManager &m_manager;
+ /** the object path of adapter */
+ std::string m_path;
+ /** the number of device for the default adapter */
+ int m_devNo;
+ /** the number of devices having reply */
+ int m_devReplies;
+
+ /** all available devices */
+ std::vector<boost::shared_ptr<BluezDevice> > m_devices;
+
+ /** represents 'DeviceRemoved' signal of org.bluez.Adapter*/
+ SignalWatch1<DBusObject_t> m_deviceRemoved;
+ /** represents 'DeviceAdded' signal of org.bluez.Adapter*/
+ SignalWatch1<DBusObject_t> m_deviceAdded;
+
+ friend class BluezDevice;
+ };
+
+ /**
+ * This class acts a proxy to org.bluez.Device.
+ * Call methods of org.bluez.Device and listen signals from it
+ * to get properties of device and track its changes
+ */
+ class BluezDevice: public DBusRemoteObject
+ {
+ public:
+ typedef map<string, boost::variant<vector<string>, string > > PropDict;
+
+ BluezDevice (BluezAdapter &adapter, const string &path);
+
+ virtual const char *getDestination() const {return "org.bluez";}
+ virtual const char *getPath() const {return m_path.c_str();}
+ virtual const char *getInterface() const {return "org.bluez.Device";}
+ virtual DBusConnection *getConnection() const {return m_adapter.m_manager.getConnection();}
+ string getMac() { return m_mac; }
+
+ /**
+ * check whether the current device has sync service
+ * if yes, put it in the adapter's sync devices list
+ */
+ void checkSyncService(const std::vector<std::string> &uuids);
+
+ private:
+ /** callback of 'GetProperties' method. The properties of the device is gotten */
+ void getPropertiesCb(const PropDict &props, const string &error);
+
+ /** callback of 'PropertyChanged' signal. Changed property is tracked */
+ void propertyChanged(const string &name, const boost::variant<vector<string>, string> &prop);
+
+ BluezAdapter &m_adapter;
+ /** the object path of the device */
+ string m_path;
+ /** name of the device */
+ string m_name;
+ /** mac address of the device */
+ string m_mac;
+ /** whether the calling of 'GetProperties' is returned */
+ bool m_reply;
+
+ typedef SignalWatch2<string, boost::variant<vector<string>, string> > PropertySignal;
+ /** represents 'PropertyChanged' signal of org.bluez.Device */
+ PropertySignal m_propertyChanged;
+
+ friend class BluezAdapter;
+ };
+
+ /*
+ * check whether the data is generated. If errors, force initilization done
+ */
+ void setDone(bool done) { m_done = done; }
+
+ /** callback of 'DefaultAdapter' method to get the default bluetooth adapter */
+ void defaultAdapterCb(const DBusObject_t &adapter, const string &error);
+
+ /** callback of 'DefaultAdapterChanged' signal to track changes of the default adapter */
+ void defaultAdapterChanged(const DBusObject_t &adapter);
+
+ DBusServer &m_server;
+ DBusConnectionPtr m_bluezConn;
+ boost::shared_ptr<BluezAdapter> m_adapter;
+
+ /** represents 'DefaultAdapterChanged' signal of org.bluez.Adapter*/
+ boost::shared_ptr<SignalWatch1<DBusObject_t> > m_adapterChanged;
+
+ /** flag to indicate whether the calls are all returned */
+ bool m_done;
+};
+
+/**
* Implements the main org.syncevolution.Server interface.
*
* All objects created by it get a reference to the creating
*/
std::list<std::pair<Caller_t, int> > m_attachedClients;
+ /* Event source that regurally pool network manager
+ * */
+ GLibEvent m_pollConnman;
/**
* The session which currently holds the main lock on the server.
* To avoid issues with concurrent modification of data or configs,
//automatic termination
AutoTerm m_autoTerm;
+ // a hash to represent matched templates for devices, the key is
+ // the peer name
+ typedef std::map<string, boost::shared_ptr<SyncConfig::TemplateDescription> > MatchedTemplates;
+
+ MatchedTemplates m_matchedTempls;
+
+ BluezManager m_bluezManager;
+
+ /** devices which have sync services */
+ SyncConfig::DeviceList m_syncDevices;
+
/**
* Watch callback for a specific client or connection.
*/
bool getTemplate,
ReadOperations::Config_t &config)
{
- ReadOperations ops(config_name);
+ ReadOperations ops(config_name, *this);
ops.getConfig(getTemplate , config);
}
uint32_t start, uint32_t count,
ReadOperations::Reports_t &reports)
{
- ReadOperations ops(config_name);
+ ReadOperations ops(config_name, *this);
ops.getReports(start, count, reports);
}
void checkSource(const std::string &configName,
const std::string &sourceName)
{
- ReadOperations ops(configName);
+ ReadOperations ops(configName, *this);
ops.checkSource(sourceName);
}
const string &sourceName,
ReadOperations::SourceDatabases_t &databases)
{
- ReadOperations ops(configName);
+ ReadOperations ops(configName, *this);
ops.getDatabases(sourceName, databases);
}
+ void getConfigs(bool getTemplates,
+ std::vector<std::string> &configNames)
+ {
+ ReadOperations ops("", *this);
+ ops.getConfigs(getTemplates, configNames);
+ }
+
/** Server.CheckPresence() */
void checkPresence(const std::string &server,
std::string &status,
const std::string &,
const std::string &> presence;
+ /**
+ * Server.TemplatesChanged, triggered each time m_syncDevices, the
+ * input for the templates, is changed
+ */
+ EmitSignal0 templatesChanged;
+
/** Server.InfoRequest */
EmitSignal6<const std::string &,
const DBusObject_t &,
const std::string &,
const std::map<string, string> &> infoRequest;
+ static gboolean connmanPoll (gpointer dbus_server);
+ DBusConnectionPtr m_connmanConn;
+
+ friend class Session;
+ class PresenceStatus {
+ bool m_httpPresence;
+ bool m_btPresence;
+ bool m_initiated;
+ DBusServer &m_server;
+
+ enum PeerStatus {
+ /* The transport is not available (local problem) */
+ NOTRANSPORT,
+ /* The peer is not contactable (remote problem) */
+ UNREACHABLE,
+ /* Not for sure whether the peer is presence but likely*/
+ MIGHTWORK,
+
+ INVALID
+ };
+
+ typedef map<string, vector<pair <string, PeerStatus> > > StatusMap;
+ typedef pair<const string, vector<pair <string, PeerStatus> > > StatusPair;
+ typedef pair <string, PeerStatus> PeerStatusPair;
+ StatusMap m_peers;
+
+ static std::string status2string (PeerStatus status) {
+ switch (status) {
+ case NOTRANSPORT:
+ return "no transport";
+ break;
+ case UNREACHABLE:
+ return "not present";
+ break;
+ case MIGHTWORK:
+ return "";
+ break;
+ case INVALID:
+ return "invalid transport status";
+ }
+ // not reached, keep compiler happy
+ return "";
+ }
+
+ public:
+ PresenceStatus (DBusServer &server)
+ :m_httpPresence (false), m_btPresence (false), m_initiated (false), m_server (server)
+ {
+ init();
+ }
+
+ void init(){
+ //initialize the configured peer list
+ if (!m_initiated) {
+ SyncConfig::ConfigList list = SyncConfig::getConfigs();
+ BOOST_FOREACH(const SyncConfig::ConfigList::value_type &server, list) {
+ SyncConfig config (server.first);
+ vector<string> urls = config.getSyncURL();
+ m_peers[server.first].clear();
+ BOOST_FOREACH (const string &url, urls) {
+ m_peers[server.first].push_back(make_pair(url,MIGHTWORK));
+ }
+ }
+ m_initiated = true;
+ }
+ }
+
+ /* Implement DBusServer::checkPresence*/
+ void checkPresence (const string &peer, string& status, std::vector<std::string> &transport) {
+
+ if (!m_initiated) {
+ //might triggered by updateConfigPeers
+ init();
+ }
+
+ string peerName = SyncConfig::normalizeConfigString (peer);
+ vector< pair<string, PeerStatus> > mytransports = m_peers[peerName];
+ if (mytransports.empty()) {
+ //wrong config name?
+ status = status2string(NOTRANSPORT);
+ transport.clear();
+ return;
+ }
+ PeerStatus mystatus = MIGHTWORK;
+ transport.clear();
+ //only if all transports are unavailable can we declare the peer
+ //status as unavailable
+ BOOST_FOREACH (PeerStatusPair &mytransport, mytransports) {
+ if (mytransport.second == MIGHTWORK) {
+ transport.push_back (mytransport.first);
+ }
+ }
+ if (transport.empty()) {
+ mystatus = NOTRANSPORT;
+ }
+ status = status2string(mystatus);
+ }
+
+ void updateConfigPeers (const std::string &peer, const ReadOperations::Config_t &config) {
+ ReadOperations::Config_t::const_iterator iter = config.find ("");
+ if (iter != config.end()) {
+ //As a simple approach, just reinitialize the whole STATUSMAP
+ //it will cause later updatePresenceStatus resend all signals
+ //and a reload in checkPresence
+ m_initiated = false;
+ }
+ }
+
+ void updatePresenceStatus (bool httpPresence, bool btPresence) {
+ bool httpChanged = (m_httpPresence != httpPresence);
+ bool btChanged = (m_btPresence != btPresence);
+ m_httpPresence = httpPresence;
+ m_btPresence = btPresence;
+
+ if (m_initiated && !httpChanged && !btChanged) {
+ //nothing changed
+ return;
+ }
+
+ //initialize the configured peer list
+ bool initiated = m_initiated;
+ if (!m_initiated) {
+ init();
+ }
+
+ //iterate all configured peers and fire singals
+ BOOST_FOREACH (StatusPair &peer, m_peers) {
+ //iterate all possible transports
+ //TODO One peer might got more than one signals, avoid this
+ std::vector<pair<string, PeerStatus> > &transports = peer.second;
+ BOOST_FOREACH (PeerStatusPair &entry, transports) {
+ string url = entry.first;
+ if (boost::starts_with (url, "http") && (httpChanged || !initiated)) {
+ entry.second = m_httpPresence ? MIGHTWORK: NOTRANSPORT;
+ m_server.presence (peer.first, status2string (entry.second), entry.first);
+ SE_LOG_DEBUG(NULL, NULL,
+ "http presence signal %s,%s,%s",
+ peer.first.c_str(),
+ status2string (entry.second).c_str(), entry.first.c_str());
+ } else if (boost::starts_with (url, "obex-bt") && (btChanged || !initiated)) {
+ entry.second = m_btPresence ? MIGHTWORK: NOTRANSPORT;
+ m_server.presence (peer.first, status2string (entry.second), entry.first);
+ SE_LOG_DEBUG(NULL, NULL,
+ "bluetooth presence signal %s,%s,%s",
+ peer.first.c_str(),
+ status2string (entry.second).c_str(), entry.first.c_str());
+ }
+ }
+ }
+ }
+ }m_presence;
+
public:
DBusServer(GMainLoop *loop, const DBusConnectionPtr &conn, int duration);
~DBusServer();
/** callback to reset for auto termination checking */
void autoTermCallback() { m_autoTerm.reset(); }
+
+ /** poll_nm callback for connman, used for presence detection*/
+ void connmanCallback(const std::map <std::string, boost::variant <std::vector <std::string> > >& props, const string &error);
+
+ PresenceStatus& getPresenceStatus() {return m_presence;}
+
+ DBusConnectionPtr getConnmanConnection() {return m_connmanConn;}
+
+ void clearPeerTempls() { m_matchedTempls.clear(); }
+ void addPeerTempl(const string &templName, const boost::shared_ptr<SyncConfig::TemplateDescription> peerTempl);
+
+ boost::shared_ptr<SyncConfig::TemplateDescription> getPeerTempl(const string &peer);
+
+ /**
+ * methods to operate device list. See DeviceList definition.
+ * The device id here is the identifier of device, the same as definition in DeviceList.
+ * In bluetooth devices, it refers to actually the mac address of the bluetooth.
+ * The finger print and match mode is used to match templates.
+ */
+ /** get sync devices */
+ void getDeviceList(SyncConfig::DeviceList &devices);
+ /** get a device according to device id. If not found, return false. */
+ bool getDevice(const string &deviceId, SyncConfig::DeviceDescription &device);
+ /** add a device */
+ void addDevice(const SyncConfig::DeviceDescription &device);
+ /** remove a device by device id. If not found, do nothing */
+ void removeDevice(const string &deviceId);
+ /** update a device with the given device information. If not found, do nothing */
+ void updateDevice(const string &deviceId, const SyncConfig::DeviceDescription &device);
};
{};
/**
+ * This class is mainly to implement two virtual functions 'askPassword'
+ * and 'savePassword' of ConfigUserInterface. The main functionality is
+ * to only get and save passwords in the gnome keyring.
+ */
+class DBusUserInterface : public SyncContext
+{
+public:
+ DBusUserInterface(const std::string &config);
+
+ /*
+ * Ask password from gnome keyring, if not found, empty string
+ * is returned
+ */
+ string askPassword(const string &passwordName,
+ const string &descr,
+ const ConfigPasswordKey &key);
+
+ //save password to gnome keyring, if not successful, false is returned.
+ bool savePassword(const string &passwordName,
+ const string &password,
+ const ConfigPasswordKey &key);
+};
+
+/**
* A running sync engine which keeps answering on D-Bus whenever
* possible and updates the Session while the sync runs.
*/
-class DBusSync : public SyncContext
+class DBusSync : public DBusUserInterface
{
Session &m_session;
virtual int sleep(int intervals);
/**
- * Implement askPassword and savePassword to retrieve
- * or save password in DBusSync.
+ * Implement askPassword to retrieve password in gnome-keyring.
+ * If not found, then ask it from dbus clients.
*/
string askPassword(const string &passwordName,
const string &descr,
const ConfigPasswordKey &key);
- bool savePassword(const string &passwordName,
- const string &password,
- const ConfigPasswordKey &key);
};
/**
/** Session.Restore() */
void restore(const string &dir, bool before,const std::vector<std::string> &sources);
+ /** Session.checkPresence() */
+ void checkPresence (string &status);
+
/**
* Must be called each time that properties changing the
* overall status are changed. Ensures that the corresponding
/***************** ReadOperations implementation ****************/
-ReadOperations::ReadOperations(const std::string &config_name) :
- m_configName(config_name)
+ReadOperations::ReadOperations(const std::string &config_name, DBusServer &server) :
+ m_configName(config_name), m_server(server)
{}
void ReadOperations::getConfigs(bool getTemplates, std::vector<std::string> &configNames)
{
if (getTemplates) {
+ // get device list from dbus server, currently only bluetooth devices
SyncConfig::DeviceList devices;
+ m_server.getDeviceList(devices);
+
+ //clear existing templates in dbus server
+ m_server.clearPeerTempls();
+
SyncConfig::TemplateList list = SyncConfig::getPeerTemplates(devices);
- BOOST_FOREACH(const boost::shared_ptr<SyncConfig::TemplateDescription> server, list) {
- configNames.push_back(server->m_name);
- //TODO create the template filters
+ std::map<std::string, int> numbers;
+ BOOST_FOREACH(const boost::shared_ptr<SyncConfig::TemplateDescription> peer, list) {
+ //if it is not a template for device
+ if(peer->m_fingerprint.empty()) {
+ configNames.push_back(peer->m_name);
+ } else {
+ string templName = "Bluetooth_";
+ templName += peer->m_id;
+ templName += "_";
+ std::map<std::string, int>::iterator it = numbers.find(peer->m_id);
+ if(it == numbers.end()) {
+ numbers.insert(std::make_pair(peer->m_id, 1));
+ templName += "1";
+ } else {
+ it->second++;
+ stringstream seq;
+ seq << it->second;
+ templName += seq.str();
+ }
+ configNames.push_back(templName);
+ m_server.addPeerTempl(templName, peer);
+ }
}
} else {
SyncConfig::ConfigList list = SyncConfig::getConfigs();
}
}
-boost::shared_ptr<SyncConfig> ReadOperations::getLocalConfig(const string &configName)
+boost::shared_ptr<DBusUserInterface> ReadOperations::getLocalConfig(const string &configName)
{
string peer, context;
SyncConfig::splitConfigString(SyncConfig::normalizeConfigString(configName),
peer, context);
- boost::shared_ptr<SyncConfig> syncConfig(new SyncConfig(configName));
+ boost::shared_ptr<DBusUserInterface> syncConfig(new DBusUserInterface(configName));
/** if config was not set temporarily */
if (!setFilters(*syncConfig)) {
Config_t &config)
{
map<string, string> localConfigs;
- boost::shared_ptr<SyncConfig> syncConfig;
+ boost::shared_ptr<SyncConfig> dbusConfig;
+ boost::shared_ptr<DBusUserInterface> dbusUI;
+ SyncConfig *syncConfig;
+ string syncURL;
/** get server template */
if(getTemplate) {
string peer, context;
- SyncConfig::splitConfigString(SyncConfig::normalizeConfigString(m_configName),
- peer, context);
- syncConfig = SyncConfig::createPeerTemplate(peer);
- if(!syncConfig.get()) {
+ boost::shared_ptr<SyncConfig::TemplateDescription> peerTemplate =
+ m_server.getPeerTempl(m_configName);
+ if(peerTemplate) {
+ SyncConfig::splitConfigString(SyncConfig::normalizeConfigString(peerTemplate->m_name),
+ peer, context);
+ dbusConfig = SyncConfig::createPeerTemplate(peerTemplate->m_path);
+ // if we have cached template information, add match information for it
+ localConfigs.insert(pair<string, string>("description", peerTemplate->m_description));
+
+ stringstream score;
+ score << peerTemplate->m_rank;
+ localConfigs.insert(pair<string, string>("score", score.str()));
+ // Actually this fingerprint is transferred by getConfigs, which refers to device name
+ localConfigs.insert(pair<string, string>("deviceName", peerTemplate->m_fingerprint));
+ // This is the fingerprint of the template
+ localConfigs.insert(pair<string, string>("fingerPrint", peerTemplate->m_matchedModel));
+
+ // if the peer is client, then replace syncURL with bluetooth
+ // MAC address
+ syncURL = "obex-bt://";
+ syncURL += peerTemplate->m_id;
+ } else {
+ SyncConfig::splitConfigString(SyncConfig::normalizeConfigString(m_configName),
+ peer, context);
+ dbusConfig = SyncConfig::createPeerTemplate(peer);
+ }
+
+ if(!dbusConfig.get()) {
SE_THROW_EXCEPTION(NoSuchConfig, "No template '" + m_configName + "' found");
}
// use the shared properties from the right context as filter
// so that the returned template preserves existing properties
- boost::shared_ptr<SyncConfig> shared = getLocalConfig(string("@") + context);
+ boost::shared_ptr<DBusUserInterface> shared = getLocalConfig(string("@") + context);
ConfigProps props;
shared->getProperties()->readProperties(props);
- syncConfig->setConfigFilter(true, "", props);
+ dbusConfig->setConfigFilter(true, "", props);
BOOST_FOREACH(std::string source, shared->getSyncSources()) {
SyncSourceNodes nodes = shared->getSyncSourceNodes(source, "");
props.clear();
nodes.getProperties()->readProperties(props);
- syncConfig->setConfigFilter(false, source, props);
+ dbusConfig->setConfigFilter(false, source, props);
}
+ syncConfig = dbusConfig.get();
} else {
- syncConfig = getLocalConfig(m_configName);
+ dbusUI = getLocalConfig(m_configName);
+ //try to check password and read password from gnome keyring if possible
+ ConfigPropertyRegistry& registry = SyncConfig::getRegistry();
+ BOOST_FOREACH(const ConfigProperty *prop, registry) {
+ prop->checkPassword(*dbusUI, m_configName, *dbusUI->getProperties());
+ }
+ list<string> configuredSources = dbusUI->getSyncSources();
+ BOOST_FOREACH(const string &sourceName, configuredSources) {
+ ConfigPropertyRegistry& registry = SyncSourceConfig::getRegistry();
+ SyncSourceNodes sourceNodes = dbusUI->getSyncSourceNodes(sourceName);
+
+ BOOST_FOREACH(const ConfigProperty *prop, registry) {
+ prop->checkPassword(*dbusUI, m_configName, *dbusUI->getProperties(),
+ sourceName, sourceNodes.getProperties());
+ }
+ }
+ syncConfig = dbusUI.get();
}
/** get sync properties and their values */
BOOST_FOREACH(const ConfigProperty *prop, syncRegistry) {
bool isDefault = false;
string value = prop->getProperty(*syncConfig->getProperties(), &isDefault);
- if(!isDefault) {
+ if(boost::iequals(prop->getName(), "syncURL") && !syncURL.empty() ) {
+ localConfigs.insert(pair<string, string>(prop->getName(), syncURL));
+ } else if(!isDefault) {
localConfigs.insert(pair<string, string>(prop->getName(), value));
}
}
try {
// this can already throw exceptions when the config is invalid
SyncSourceParams params(sourceName, config->getSyncSourceNodes(sourceName));
- auto_ptr<SyncSource> syncSource(SyncSource::createSource(params, false));
+ auto_ptr<SyncSource> syncSource(SyncSource::createSource(params, false, config.get()));
if (syncSource.get()) {
syncSource->open();
SE_THROW_EXCEPTION(NoSuchSource, "'" + m_configName + "' has no '" + sourceName + "' source");
}
+/***************** DBusUserInterface implementation **********************/
+DBusUserInterface::DBusUserInterface(const std::string &config):
+ SyncContext(config, true)
+{
+}
+
+inline const char *passwdStr(const std::string &str)
+{
+ return str.empty() ? NULL : str.c_str();
+}
+
+string DBusUserInterface::askPassword(const string &passwordName,
+ const string &descr,
+ const ConfigPasswordKey &key)
+{
+ string password;
+#ifdef USE_GNOME_KEYRING
+ /** here we use server sync url without protocol prefix and
+ * user account name as the key in the keyring */
+ /* It is possible to let CmdlineSyncClient decide which of fields in ConfigPasswordKey it would use
+ * but currently only use passed key instead */
+ GnomeKeyringResult result;
+ GList* list;
+
+ result = gnome_keyring_find_network_password_sync(passwdStr(key.user),
+ passwdStr(key.domain),
+ passwdStr(key.server),
+ passwdStr(key.object),
+ passwdStr(key.protocol),
+ passwdStr(key.authtype),
+ key.port,
+ &list);
+
+ /** if find password stored in gnome keyring */
+ if(result == GNOME_KEYRING_RESULT_OK && list && list->data ) {
+ GnomeKeyringNetworkPasswordData *key_data;
+ key_data = (GnomeKeyringNetworkPasswordData*)list->data;
+ password = key_data->password;
+ gnome_keyring_network_password_list_free(list);
+ return password;
+ }
+#endif
+ //if not found, return empty
+ return "";
+}
+
+bool DBusUserInterface::savePassword(const string &passwordName,
+ const string &password,
+ const ConfigPasswordKey &key)
+{
+#ifdef USE_GNOME_KEYRING
+ /* It is possible to let CmdlineSyncClient decide which of fields in ConfigPasswordKey it would use
+ * but currently only use passed key instead */
+ guint32 itemId;
+ GnomeKeyringResult result;
+ // write password to keyring
+ result = gnome_keyring_set_network_password_sync(NULL,
+ passwdStr(key.user),
+ passwdStr(key.domain),
+ passwdStr(key.server),
+ passwdStr(key.object),
+ passwdStr(key.protocol),
+ passwdStr(key.authtype),
+ key.port,
+ password.c_str(),
+ &itemId);
+ /* if set operation is failed */
+ if(result != GNOME_KEYRING_RESULT_OK) {
+#ifdef GNOME_KEYRING_220
+ SyncContext::throwError("Try to save " + passwordName + " in gnome-keyring but get an error. " + gnome_keyring_result_to_message(result));
+#else
+ /** if gnome-keyring version is below 2.20, it doesn't support 'gnome_keyring_result_to_message'. */
+ stringstream value;
+ value << (int)result;
+ SyncContext::throwError("Try to save " + passwordName + " in gnome-keyring but get an error. The gnome-keyring error code is " + value.str() + ".");
+#endif
+ }
+ return true;
+#else
+ /** if no support of gnome-keyring, don't save anything */
+ return false;
+#endif
+}
+
+
/***************** DBusSync implementation **********************/
DBusSync::DBusSync(const std::string &config,
Session &session) :
- SyncContext(config, true),
+ DBusUserInterface(config),
m_session(session)
{
}
} else {
// no connection, use HTTP via libsoup/GMainLoop
GMainLoop *loop = m_session.getServer().getLoop();
- g_main_loop_ref(loop);
- boost::shared_ptr<HTTPTransportAgent> agent(new SoupTransportAgent(loop));
- agent->setConfig(*this);
+ boost::shared_ptr<TransportAgent> agent = SyncContext::createTransportAgent(loop);
return agent;
}
}
}
}
-inline const char *passwdStr(const std::string &str)
-{
- return str.empty() ? NULL : str.c_str();
-}
-
string DBusSync::askPassword(const string &passwordName,
const string &descr,
const ConfigPasswordKey &key)
{
- string password;
-#ifdef USE_GNOME_KEYRING
- /** here we use server sync url without protocol prefix and
- * user account name as the key in the keyring */
- /* It is possible to let CmdlineSyncClient decide which of fields in ConfigPasswordKey it would use
- * but currently only use passed key instead */
- GnomeKeyringResult result;
- GList* list;
+ string password = DBusUserInterface::askPassword(passwordName, descr, key);
- result = gnome_keyring_find_network_password_sync(passwdStr(key.user),
- passwdStr(key.domain),
- passwdStr(key.server),
- passwdStr(key.object),
- passwdStr(key.protocol),
- passwdStr(key.authtype),
- key.port,
- &list);
-
- /** if find password stored in gnome keyring */
- if(result == GNOME_KEYRING_RESULT_OK && list && list->data ) {
- GnomeKeyringNetworkPasswordData *key_data;
- key_data = (GnomeKeyringNetworkPasswordData*)list->data;
- password = key_data->password;
- gnome_keyring_network_password_list_free(list);
- return password;
+ if(password.empty()) {
+ password = m_session.askPassword(passwordName, descr, key);
}
- //if not found, then ask user to interactively input password
-#endif
- /**
- * if not built with gnome_keyring support, directly send password request
- * to dbus clients
- */
- return m_session.askPassword(passwordName, descr, key);
-}
-
-bool DBusSync::savePassword(const string &passwordName,
- const string &password,
- const ConfigPasswordKey &key)
-{
-#ifdef USE_GNOME_KEYRING
- /* It is possible to let CmdlineSyncClient decide which of fields in ConfigPasswordKey it would use
- * but currently only use passed key instead */
- guint32 itemId;
- GnomeKeyringResult result;
- // write password to keyring
- result = gnome_keyring_set_network_password_sync(NULL,
- passwdStr(key.user),
- passwdStr(key.domain),
- passwdStr(key.server),
- passwdStr(key.object),
- passwdStr(key.protocol),
- passwdStr(key.authtype),
- key.port,
- password.c_str(),
- &itemId);
- /* if set operation is failed */
- if(result != GNOME_KEYRING_RESULT_OK) {
-#ifdef GNOME_KEYRING_220
- SyncContext::throwError("Try to save " + passwordName + " in gnome-keyring but get an error. " + gnome_keyring_result_to_message(result));
-#else
- /** if gnome-keyring version is below 2.20, it doesn't support 'gnome_keyring_result_to_message'. */
- stringstream value;
- value << (int)result;
- SyncContext::throwError("Try to save " + passwordName + " in gnome-keyring but get an error. The gnome-keyring error code is " + value.str() + ".");
-#endif
- }
- return true;
-#else
- /** if no support of gnome-keyring, don't save anything */
- return false;
-#endif
+ return password;
}
/***************** Session implementation ***********************/
throw std::runtime_error("Clearing existing configuration and temporary configuration changes which only affects the duration of the session are mutually exclusive");
}
+ m_server.getPresenceStatus().updateConfigPeers (m_configName, config);
/** check whether we need remove the entire configuration */
if(!update && config.empty()) {
boost::shared_ptr<SyncConfig> syncConfig(new SyncConfig(getConfigName()));
std::string("/org/syncevolution/Session/") + session,
"org.syncevolution.Session",
boost::bind(&DBusServer::autoTermCallback, &server)),
- ReadOperations(config_name),
+ ReadOperations(config_name, server),
m_server(server),
m_sessionID(session),
m_peerDeviceID(peerDeviceID),
emitProgress(*this, "ProgressChanged")
{
add(this, &Session::detach, "Detach");
- add(&ReadOperations::getConfigs, "GetConfigs");
+ add(static_cast<ReadOperations *>(this), &ReadOperations::getConfigs, "GetConfigs");
add(static_cast<ReadOperations *>(this), &ReadOperations::getConfig, "GetConfig");
add(this, &Session::setConfig, "SetConfig");
add(static_cast<ReadOperations *>(this), &ReadOperations::getReports, "GetReports");
add(this, &Session::getStatus, "GetStatus");
add(this, &Session::getProgress, "GetProgress");
add(this, &Session::restore, "Restore");
+ add(this, &Session::checkPresence, "checkPresence");
add(emitStatus);
add(emitProgress);
}
return "";
}
+/*Implementation of Session.CheckPresence */
+void Session::checkPresence (string &status)
+{
+ vector<string> transport;
+ m_server.m_presence.checkPresence (m_configName, status, transport);
+}
+
/************************ ProgressData implementation *****************/
ProgressData::ProgressData(int32_t &progress)
: m_progress(progress),
BOOST_FOREACH(const SyncConfig::ConfigList::value_type &server,
servers) {
SyncConfig conf(server.first);
- if (conf.getSyncURL() == serverID) {
- config = server.first;
+ vector<string> urls = conf.getSyncURL();
+ BOOST_FOREACH (const string &url, urls) {
+ if (url == serverID) {
+ config = server.first;
+ break;
+ }
+ }
+ if (!config.empty()) {
break;
}
}
BOOST_FOREACH(const SyncConfig::ConfigList::value_type &server,
servers) {
SyncConfig conf(server.first);
- string url = conf.getSyncURL();
- url = url.substr (0, url.find("+"));
- SE_LOG_DEBUG (NULL, NULL, "matching against %s",url.c_str());
- //TODO working with multiple SyncURLs
- if (url.find ("obex-bt://") ==0 && url.substr(strlen("obex-bt://"), url.npos) == btAddr) {
- config = server.first;
+ vector<string> urls = conf.getSyncURL();
+ BOOST_FOREACH (string &url, urls){
+ url = url.substr (0, url.find("+"));
+ SE_LOG_DEBUG (NULL, NULL, "matching against %s",url.c_str());
+ if (url.find ("obex-bt://") ==0 && url.substr(strlen("obex-bt://"), url.npos) == btAddr) {
+ config = server.first;
+ break;
+ }
+ }
+ if (!config.empty()){
break;
- }
+ }
}
}
}
std::string &status,
std::vector<std::string> &transports)
{
- // TODO: implement this, right now always return status = "" = available
+ return m_presence.checkPresence(server, status, transports);
}
void DBusServer::getSessions(std::vector<std::string> &sessions)
m_activeSession(NULL),
m_lastInfoReq(0),
m_autoTerm(duration),
+ m_bluezManager(*this),
sessionChanged(*this, "SessionChanged"),
presence(*this, "Presence"),
- infoRequest(*this, "InfoRequest")
+ templatesChanged(*this, "TemplatesChanged"),
+ infoRequest(*this, "InfoRequest"),
+ m_presence(*this)
{
struct timeval tv;
gettimeofday(&tv, NULL);
add(this, &DBusServer::detachClient, "Detach");
add(this, &DBusServer::connect, "Connect");
add(this, &DBusServer::startSession, "StartSession");
- add(&ReadOperations::getConfigs, "GetConfigs");
+ add(this, &DBusServer::getConfigs, "GetConfigs");
add(this, &DBusServer::getConfig, "GetConfig");
add(this, &DBusServer::getReports, "GetReports");
add(this, &DBusServer::checkSource, "CheckSource");
add(this, &DBusServer::getSessions, "GetSessions");
add(this, &DBusServer::infoResponse, "InfoResponse");
add(sessionChanged);
+ add(templatesChanged);
add(presence);
add(infoRequest);
+
+ const char *connmanTest = getenv ("DBUS_TEST_CONNMAN");
+ m_connmanConn = g_dbus_setup_bus (connmanTest ? DBUS_BUS_SESSION: DBUS_BUS_SYSTEM, NULL, true, NULL);
+ if (m_connmanConn) {
+ m_pollConnman = g_timeout_add_seconds (10, connmanPoll, static_cast <gpointer> (this));
+ }
+
}
DBusServer::~DBusServer()
}
}
+gboolean DBusServer::connmanPoll (gpointer dbusserver)
+{
+ DBusServer *me = static_cast<DBusServer *>(dbusserver);
+ DBusConnectionPtr conn = me->getConnmanConnection();
+ struct ConnmanClient : public DBusCallObject
+ {
+ DBusConnectionPtr m_connection;
+ ConnmanClient (DBusConnectionPtr conn ) : m_connection (conn) {}
+ virtual const char *getDestination() const {return "org.moblin.connman";}
+ virtual const char *getPath() const {return "/";}
+ virtual const char *getInterface() const {return "org.moblin.connman.Manager";}
+ virtual const char *getMethod() const {return "GetProperties"; }
+ virtual DBusConnection *getConnection() const {return m_connection.get();}
+ }connman (conn);
+
+ typedef std::map <std::string, boost::variant <std::vector <std::string> > > PropDict;
+ DBusClientCall0<PropDict> getProp(connman);
+ getProp (boost::bind(&DBusServer::connmanCallback, me, _1, _2));
+ return TRUE;
+}
+
+
+void DBusServer::connmanCallback (const std::map <std::string, boost::variant <std::vector <std::string> > >& props, const string &error)
+{
+ if (!error.empty()) {
+ if (error == "org.freedesktop.DBus.Error.ServiceUnknown") {
+ // no connman available, remove connmanPoll.
+ m_pollConnman.set(0);
+ // ensure there is still first set of singal set in case of no
+ // connman available
+ m_presence.updatePresenceStatus (true, true);
+ SE_LOG_DEBUG (NULL, NULL, "No connman service available %s", error.c_str());
+ return;
+ }
+ SE_LOG_DEBUG (NULL, NULL, "error in connmanCallback %s", error.c_str());
+ return;
+ }
+
+ typedef std::pair <std::string, boost::variant <std::vector <std::string> > > element;
+ bool httpPresence = false, btPresence = false;
+ BOOST_FOREACH (element entry, props) {
+ //match connected for HTTP based peers (wifi/wimax/ethernet)
+ if (entry.first == "ConnectedTechnologies") {
+ std::vector <std::string> connected = boost::get <std::vector <std::string> > (entry.second);
+ BOOST_FOREACH (std::string tech, connected) {
+ if (boost::iequals (tech, "wifi") || boost::iequals (tech, "ethernet")
+ || boost::iequals (tech, "wimax")) {
+ httpPresence = true;
+ break;
+ }
+ }
+ } else if (entry.first == "EnabledTechnologies") {
+ std::vector <std::string> enabled = boost::get <std::vector <std::string> > (entry.second);
+ BOOST_FOREACH (std::string tech, enabled){
+ if (boost::iequals (tech, "bluetooth")) {
+ btPresence = true;
+ break;
+ }
+ }
+ } else {
+ continue;
+ }
+ }
+ //now delivering the signals
+ m_presence.updatePresenceStatus (httpPresence, btPresence);
+}
+
+void DBusServer::getDeviceList(SyncConfig::DeviceList &devices)
+{
+ //wait bluez or other device managers
+ while(!m_bluezManager.isDone()) {
+ g_main_loop_run(m_loop);
+ }
+
+ devices.clear();
+ devices = m_syncDevices;
+}
+
+void DBusServer::addPeerTempl(const string &templName,
+ const boost::shared_ptr<SyncConfig::TemplateDescription> peerTempl)
+{
+ std::string lower = templName;
+ boost::to_lower(lower);
+ m_matchedTempls.insert(MatchedTemplates::value_type(lower, peerTempl));
+}
+
+boost::shared_ptr<SyncConfig::TemplateDescription> DBusServer::getPeerTempl(const string &peer)
+{
+ std::string lower = peer;
+ boost::to_lower(lower);
+ MatchedTemplates::iterator it = m_matchedTempls.find(lower);
+ if(it != m_matchedTempls.end()) {
+ return it->second;
+ } else {
+ return boost::shared_ptr<SyncConfig::TemplateDescription>();
+ }
+}
+
+bool DBusServer::getDevice(const string &deviceId, SyncConfig::DeviceDescription &device)
+{
+ SyncConfig::DeviceList::iterator syncDevIt;
+ for(syncDevIt = m_syncDevices.begin(); syncDevIt != m_syncDevices.end(); ++syncDevIt) {
+ if(boost::equals(syncDevIt->m_deviceId, deviceId)) {
+ device = *syncDevIt;
+ return true;
+ }
+ }
+ return false;
+}
+
+void DBusServer::addDevice(const SyncConfig::DeviceDescription &device)
+{
+ SyncConfig::DeviceList::iterator it;
+ for(it = m_syncDevices.begin(); it != m_syncDevices.end(); ++it) {
+ if(boost::iequals(it->m_deviceId, device.m_deviceId)) {
+ break;
+ }
+ }
+ if(it == m_syncDevices.end()) {
+ m_syncDevices.push_back(device);
+ templatesChanged();
+ }
+}
+
+void DBusServer::removeDevice(const string &deviceId)
+{
+ SyncConfig::DeviceList::iterator syncDevIt;
+ for(syncDevIt = m_syncDevices.begin(); syncDevIt != m_syncDevices.end(); ++syncDevIt) {
+ if(boost::equals(syncDevIt->m_deviceId, deviceId)) {
+ m_syncDevices.erase(syncDevIt);
+ templatesChanged();
+ break;
+ }
+ }
+}
+
+void DBusServer::updateDevice(const string &deviceId,
+ const SyncConfig::DeviceDescription &device)
+{
+ SyncConfig::DeviceList::iterator it;
+ for(it = m_syncDevices.begin(); it != m_syncDevices.end(); ++it) {
+ if(boost::iequals(it->m_deviceId, deviceId)) {
+ (*it) = device;
+ templatesChanged();
+ break;
+ }
+ }
+}
+
/********************** InfoReq implementation ******************/
InfoReq::InfoReq(DBusServer &server,
const string &type,
}
}
+/********************** BluezManager implementation ******************/
+BluezManager::BluezManager(DBusServer &server) :
+ m_server(server)
+{
+ m_bluezConn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, true, NULL);
+ if(m_bluezConn) {
+ m_done = false;
+ DBusClientCall0<DBusObject_t> getAdapter(*this, "DefaultAdapter");
+ getAdapter(boost::bind(&BluezManager::defaultAdapterCb, this, _1, _2 ));
+ m_adapterChanged.reset(new SignalWatch1<DBusObject_t>(*this, "DefaultAdapterChanged"));
+ (*m_adapterChanged)(boost::bind(&BluezManager::defaultAdapterChanged, this, _1));
+ } else {
+ m_done = true;
+ }
+}
+
+void BluezManager::defaultAdapterChanged(const DBusObject_t &adapter)
+{
+ m_done = false;
+ //remove devices that belong to this original adapter
+ if(m_adapter) {
+ BOOST_FOREACH(boost::shared_ptr<BluezDevice> &device, m_adapter->getDevices()) {
+ m_server.removeDevice(device->getMac());
+ }
+ }
+ string error;
+ defaultAdapterCb(adapter, error);
+}
+
+void BluezManager::defaultAdapterCb(const DBusObject_t &adapter, const string &error)
+{
+ if(!error.empty()) {
+ SE_LOG_DEBUG (NULL, NULL, "Error in calling DefaultAdapter of Interface org.bluez.Manager: %s", error.c_str());
+ m_done = true;
+ return;
+ }
+ m_adapter.reset(new BluezAdapter(*this, adapter));
+}
+
+BluezManager::BluezAdapter::BluezAdapter(BluezManager &manager, const string &path)
+ : m_manager(manager), m_path(path), m_devNo(0), m_devReplies(0),
+ m_deviceRemoved(*this, "DeviceRemoved"), m_deviceAdded(*this, "DeviceCreated")
+{
+ DBusClientCall0<std::vector<DBusObject_t> > listDevices(*this, "ListDevices");
+ listDevices(boost::bind(&BluezAdapter::listDevicesCb, this, _1, _2));
+ //m_deviceRemoved.reset(new SignalWatch1<DBusObject_t>(*this, "DeviceRemoved"));
+ m_deviceRemoved(boost::bind(&BluezAdapter::deviceRemoved, this, _1));
+
+ //m_deviceAdded.reset(new SignalWatch1<DBusObject_t>(*this, "DeviceCreated"));
+ m_deviceAdded(boost::bind(&BluezAdapter::deviceCreated, this, _1));
+}
+
+void BluezManager::BluezAdapter::listDevicesCb(const std::vector<DBusObject_t> &devices, const string &error)
+{
+ if(!error.empty()) {
+ SE_LOG_DEBUG (NULL, NULL, "Error in calling ListDevices of Interface org.bluez.Adapter: %s", error.c_str());
+ checkDone(true);
+ return;
+ }
+ m_devNo = devices.size();
+ BOOST_FOREACH(const DBusObject_t &device, devices) {
+ boost::shared_ptr<BluezDevice> bluezDevice(new BluezDevice(*this, device));
+ m_devices.push_back(bluezDevice);
+ }
+ checkDone();
+}
+
+void BluezManager::BluezAdapter::deviceRemoved(const DBusObject_t &object)
+{
+ string address;
+ std::vector<boost::shared_ptr<BluezDevice> >::iterator devIt;
+ for(devIt = m_devices.begin(); devIt != m_devices.end(); ++devIt) {
+ if(boost::equals((*devIt)->getPath(), object)) {
+ address = (*devIt)->m_mac;
+ if((*devIt)->m_reply) {
+ m_devReplies--;
+ }
+ m_devNo--;
+ m_devices.erase(devIt);
+ break;
+ }
+ }
+ m_manager.m_server.removeDevice(address);
+}
+
+void BluezManager::BluezAdapter::deviceCreated(const DBusObject_t &object)
+{
+ m_devNo++;
+ boost::shared_ptr<BluezDevice> bluezDevice(new BluezDevice(*this, object));
+ m_devices.push_back(bluezDevice);
+}
+
+BluezManager::BluezDevice::BluezDevice (BluezAdapter &adapter, const string &path)
+ : m_adapter(adapter), m_path(path), m_reply(false), m_propertyChanged(*this, "PropertyChanged")
+{
+ DBusClientCall0<PropDict> getProperties(*this, "GetProperties");
+ getProperties(boost::bind(&BluezDevice::getPropertiesCb, this, _1, _2));
+
+ m_propertyChanged(boost::bind(&BluezDevice::propertyChanged, this, _1, _2));
+}
+
+void BluezManager::BluezDevice::checkSyncService(const std::vector<std::string> &uuids)
+{
+ static const char * SYNCML_CLIENT_UUID = "00000002-0000-1000-8000-0002ee000002";
+ bool hasSyncService = false;
+ DBusServer &server = m_adapter.m_manager.m_server;
+ BOOST_FOREACH(const string &uuid, uuids) {
+ //if the device has sync service, add it to the device list
+ if(boost::iequals(uuid, SYNCML_CLIENT_UUID)) {
+ hasSyncService = true;
+ if(!m_mac.empty()) {
+ server.addDevice(SyncConfig::DeviceDescription(m_mac, m_name, SyncConfig::MATCH_FOR_SERVER_MODE));
+ }
+ break;
+ }
+ }
+ // if sync service is not available now, possible to remove device
+ if(!hasSyncService && !m_mac.empty()) {
+ server.removeDevice(m_mac);
+ }
+}
+
+void BluezManager::BluezDevice::getPropertiesCb(const PropDict &props, const string &error)
+{
+ m_adapter.m_devReplies++;
+ m_reply = true;
+ if(!error.empty()) {
+ SE_LOG_DEBUG (NULL, NULL, "Error in calling GetProperties of Interface org.bluez.Device: %s", error.c_str());
+ } else {
+ PropDict::const_iterator it = props.find("Name");
+ if(it != props.end()) {
+ m_name = boost::get<string>(it->second);
+ }
+ it = props.find("Address");
+ if(it != props.end()) {
+ m_mac = boost::get<string>(it->second);
+ }
+
+ PropDict::const_iterator uuids = props.find("UUIDs");
+ if(uuids != props.end()) {
+ const std::vector<std::string> uuidVec = boost::get<std::vector<std::string> >(uuids->second);
+ checkSyncService(uuidVec);
+ }
+ }
+ m_adapter.checkDone();
+}
+
+void BluezManager::BluezDevice::propertyChanged(const string &name,
+ const boost::variant<vector<string>, string> &prop)
+{
+ DBusServer &server = m_adapter.m_manager.m_server;
+ if(boost::iequals(name, "Name")) {
+ m_name = boost::get<std::string>(prop);
+ SyncConfig::DeviceDescription device;
+ if(server.getDevice(m_mac, device)) {
+ device.m_fingerprint = m_name;
+ server.updateDevice(m_mac, device);
+ }
+ } else if(boost::iequals(name, "UUIDs")) {
+ const std::vector<std::string> uuidVec = boost::get<std::vector<std::string> >(prop);
+ checkSyncService(uuidVec);
+ } else if(boost::iequals(name, "Address")) {
+ string mac = boost::get<std::string>(prop);
+ SyncConfig::DeviceDescription device;
+ if(server.getDevice(m_mac, device)) {
+ device.m_deviceId = mac;
+ server.updateDevice(m_mac, device);
+ }
+ m_mac = mac;
+ }
+}
+
/**************************** main *************************/
void niam(int sig)
SyncConfig::getPeerTemplates(devices), false);
} else {
//limiting at templates for syncml clients only.
- devices.push_back (SyncConfig::DeviceList::value_type (m_template, SyncConfig::MATCH_FOR_SERVER_MODE));
+ devices.push_back (SyncConfig::DeviceDescription("", m_template, SyncConfig::MATCH_FOR_SERVER_MODE));
dumpConfigTemplates("Available configuration templates:",
SyncConfig::matchPeerTemplates(devices), true);
}
"peers/scheduleworld/config.ini:ConsumerReady = 1\n"
"peers/scheduleworld/sources/addressbook/.internal.ini:# adminData = \n"
+ "peers/scheduleworld/sources/addressbook/.internal.ini:# synthesisID = 0\n"
"peers/scheduleworld/sources/addressbook/config.ini:sync = two-way\n"
"sources/addressbook/config.ini:type = addressbook:text/vcard\n"
"peers/scheduleworld/sources/addressbook/config.ini:type = addressbook:text/vcard\n"
"sources/addressbook/config.ini:# evolutionpassword = \n"
"peers/scheduleworld/sources/calendar/.internal.ini:# adminData = \n"
+ "peers/scheduleworld/sources/calendar/.internal.ini:# synthesisID = 0\n"
"peers/scheduleworld/sources/calendar/config.ini:sync = two-way\n"
"sources/calendar/config.ini:type = calendar\n"
"peers/scheduleworld/sources/calendar/config.ini:type = calendar\n"
"sources/calendar/config.ini:# evolutionpassword = \n"
"peers/scheduleworld/sources/memo/.internal.ini:# adminData = \n"
+ "peers/scheduleworld/sources/memo/.internal.ini:# synthesisID = 0\n"
"peers/scheduleworld/sources/memo/config.ini:sync = two-way\n"
"sources/memo/config.ini:type = memo\n"
"peers/scheduleworld/sources/memo/config.ini:type = memo\n"
"sources/memo/config.ini:# evolutionpassword = \n"
"peers/scheduleworld/sources/todo/.internal.ini:# adminData = \n"
+ "peers/scheduleworld/sources/todo/.internal.ini:# synthesisID = 0\n"
"peers/scheduleworld/sources/todo/config.ini:sync = two-way\n"
"sources/todo/config.ini:type = todo\n"
"peers/scheduleworld/sources/todo/config.ini:type = todo\n"
string expected = ScheduleWorldConfig();
expected += "\n"
"peers/scheduleworld/sources/xyz/.internal.ini:# adminData = \n"
- "peers/scheduleworld/sources/xyz/config.ini:# sync = two-way\n"
+ "peers/scheduleworld/sources/xyz/.internal.ini:# synthesisID = 0\n"
+ "peers/scheduleworld/sources/xyz/config.ini:# sync = disabled\n"
"peers/scheduleworld/sources/xyz/config.ini:# type = select backend\n"
"peers/scheduleworld/sources/xyz/config.ini:uri = dummy\n"
"sources/xyz/config.ini:# type = select backend\n"
"ConfigDate" +
"deviceData" +
"adminData" +
+ "synthesisID" +
"lastNonce" +
"last";
BOOST_FOREACH(string &prop, props) {
"todo/config.ini:sync = disabled");
return config;
- }
-
- /** temporarily set env variable, restore old value on destruction */
- class ScopedEnvChange {
- public:
- ScopedEnvChange(const string &var, const string &value) :
- m_var(var)
- {
- const char *oldval = getenv(var.c_str());
- if (oldval) {
- m_oldvalset = true;
- m_oldval = oldval;
- } else {
- m_oldvalset = false;
- }
- setenv(var.c_str(), value.c_str(), 1);
- }
- ~ScopedEnvChange()
- {
- if (m_oldvalset) {
- setenv(m_var.c_str(), m_oldval.c_str(), 1);
- } else {
- unsetenv(m_var.c_str());
- }
- }
- private:
- string m_var, m_oldval;
- bool m_oldvalset;
- };
-
+ }
/** create directory hierarchy, overwriting previous content */
void createFiles(const string &root, const string &content, bool append = false) {
}
bool getProperty(const string &property,
- string &value) {
+ string &value) const {
value = readProperty(property);
return !value.empty();
}
bool getProperty(const string &property,
- bool &value) {
+ bool &value) const {
std::string str = readProperty(property);
if (str.empty()) {
return false;
}
template <class T> bool getProperty(const string &property,
- T &value) {
+ T &value) const {
std::string str = readProperty(property);
if (str.empty()) {
return false;
AM_CPPFLAGS = @BACKEND_CPPFLAGS@ @GLIB_CFLAGS@ -I$(top_srcdir)/test -I$(top_srcdir)/src -DSYNCEVO_BACKEND=\"$(backendsearchdir)\"
+SUBDIRS = configs
+
# applies to sources in SyncEvolution repository, but not
# the Funambol C++ client library
SYNCEVOLUTION_CXXFLAGS = @SYNCEVOLUTION_CXXFLAGS@
\
SynthesisDBPlugin.cpp \
\
- SyncEvolutionXML.c \
SyncContext.h \
SyncContext.cpp \
\
EXTRA_DIST =syncevolution.pc.in
libsyncevolution_la_SOURCES = $(SYNCEVOLUTION_SOURCES)
-libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ $(SYNTHESIS_LIBS) $(TRANSPORT_LIBS) @LIBS@ $(SYNCEVOLUTION_LDADD)
-libsyncevolution_la_CXXFLAGS = $(TRANSPORT_CFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(SYNTHESIS_CFLAGS)
-libsyncevolution_la_CPPFLAGS = $(AM_CPPFLAGS) -DTEMPLATE_DIR=\""$(datadir)/syncevolution/templates"\" -DLIBDIR=\""$(libdir)"\"
+nodist_libsyncevolution_la_SOURCES = SyncEvolutionXML.c
+CLEANFILES = SyncEvolutionXML.c
+libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ $(SYNTHESIS_LIBS) $(TRANSPORT_LIBS) @LIBS@ $(SYNCEVOLUTION_LDADD) $(NSS_LIBS)
+libsyncevolution_la_CXXFLAGS = $(TRANSPORT_CFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(SYNTHESIS_CFLAGS) $(NSS_CFLAGS)
+libsyncevolution_la_CPPFLAGS = $(AM_CPPFLAGS) \
+ -DXML_CONFIG_DIR=\""$(datadir)/syncevolution/xml"\" \
+ -DTEMPLATE_DIR=\""$(datadir)/syncevolution/templates"\" \
+ -DLIBDIR=\""$(libdir)"\"
libsyncevolution_la_DEPENDENCIES = $(SYNTHESIS_DEP)
if ENABLE_MODULES
libsyncevolution_la_LDFLAGS = -static
endif
-SyncEvolutionXML.c: $(srcdir)/../syncclient_sample_config.xml
- echo "const char *SyncEvolutionXML =" > $@
- sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' $< >>$@
- echo ";" >>$@
+# command which embeds its input lines into a C-style string that runs across multiple lines
+TO_C_STRING = sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/'
+
+# Don't depend on specific XML files. Instead recreate
+# SyncEvolutionXML.c each time make is invoked (allows including new
+# fragments in the binary without rerunning configure).
+SyncEvolutionXML.c: GenSyncEvolutionXML
+.PHONY: GenSyncEvolutionXML
+GenSyncEvolutionXML:
+ echo "const char *SyncEvolutionXMLClient =" > SyncEvolutionXML.c.new
+ (cd $(srcdir)/configs && perl update-samples.pl syncevolution.xml client ) | \
+ perl -p -e 's;</datatypes>; <fieldlists/>\n <profiles/>\n <datatypedefs/>\n </datatypes>;' | \
+ $(TO_C_STRING) >>SyncEvolutionXML.c.new
+ echo ";" >>SyncEvolutionXML.c.new
+ echo "const char *SyncEvolutionXMLClientRules =" >> SyncEvolutionXML.c.new
+ (cd $(srcdir)/configs && cat remoterules/*.xml remoterules/client/*.xml) | $(TO_C_STRING) >>SyncEvolutionXML.c.new
+ echo ";" >>SyncEvolutionXML.c.new
+ if cmp SyncEvolutionXML.c SyncEvolutionXML.c.new >/dev/null; then rm SyncEvolutionXML.c.new; else mv SyncEvolutionXML.c.new SyncEvolutionXML.c; fi
+
# include boost in distribution
#dist-hook:
CurlTransportAgent.h CurlTransportAgent.cpp \
SoupTransportAgent.h SoupTransportAgent.cpp util.cpp util.h \
lcs.h lcs.cpp Cmdline.cpp Cmdline.h SyncSource.h \
- SyncSource.cpp SynthesisDBPlugin.cpp SyncEvolutionXML.c \
- SyncContext.h SyncContext.cpp SyncConfig.h SyncConfig.cpp \
+ SyncSource.cpp SynthesisDBPlugin.cpp SyncContext.h \
+ SyncContext.cpp SyncConfig.h SyncConfig.cpp \
DevNullConfigNode.h MultiplexConfigNode.h \
MultiplexConfigNode.cpp FilterConfigNode.h \
FilterConfigNode.cpp SafeConfigNode.h SafeConfigNode.cpp \
libsyncevolution_la-Cmdline.lo \
libsyncevolution_la-SyncSource.lo \
libsyncevolution_la-SynthesisDBPlugin.lo \
- libsyncevolution_la-SyncEvolutionXML.lo \
libsyncevolution_la-SyncContext.lo \
libsyncevolution_la-SyncConfig.lo \
libsyncevolution_la-MultiplexConfigNode.lo \
libsyncevolution_la-FileConfigTree.lo \
libsyncevolution_la-TrackingSyncSource.lo $(am__objects_1)
am_libsyncevolution_la_OBJECTS = $(am__objects_2)
-libsyncevolution_la_OBJECTS = $(am_libsyncevolution_la_OBJECTS)
+nodist_libsyncevolution_la_OBJECTS = \
+ libsyncevolution_la-SyncEvolutionXML.lo
+libsyncevolution_la_OBJECTS = $(am_libsyncevolution_la_OBJECTS) \
+ $(nodist_libsyncevolution_la_OBJECTS)
libsyncevolution_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) \
$(libsyncevolution_la_CXXFLAGS) $(CXXFLAGS) \
CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
-SOURCES = $(libsyncevolution_la_SOURCES)
+SOURCES = $(libsyncevolution_la_SOURCES) \
+ $(nodist_libsyncevolution_la_SOURCES)
DIST_SOURCES = $(am__libsyncevolution_la_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
pkgconfigDATA_INSTALL = $(INSTALL_DATA)
DATA = $(pkgconfig_DATA)
libsyncevolution_includeHEADERS_INSTALL = $(INSTALL_HEADER)
HEADERS = $(libsyncevolution_include_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
ETAGS = etags
CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ADDRESSBOOK_CFLAGS = @ADDRESSBOOK_CFLAGS@
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = @BACKEND_CPPFLAGS@ @GLIB_CFLAGS@ -I$(top_srcdir)/test -I$(top_srcdir)/src -DSYNCEVO_BACKEND=\"$(backendsearchdir)\"
+SUBDIRS = configs
MAINTAINERCLEANFILES = Makefile.in
lib_LTLIBRARIES = libsyncevolution.la
SYNCEVOLUTION_SOURCES = ConfigTree.h ConfigNode.h HashConfigNode.h \
CurlTransportAgent.cpp SoupTransportAgent.h \
SoupTransportAgent.cpp util.cpp util.h lcs.h lcs.cpp \
Cmdline.cpp Cmdline.h SyncSource.h SyncSource.cpp \
- SynthesisDBPlugin.cpp SyncEvolutionXML.c SyncContext.h \
- SyncContext.cpp SyncConfig.h SyncConfig.cpp \
- DevNullConfigNode.h MultiplexConfigNode.h \
- MultiplexConfigNode.cpp FilterConfigNode.h \
- FilterConfigNode.cpp SafeConfigNode.h SafeConfigNode.cpp \
- PrefixConfigNode.h PrefixConfigNode.cpp FileConfigNode.h \
- FileConfigNode.cpp FileConfigTree.h FileConfigTree.cpp \
- TrackingSyncSource.h TrackingSyncSource.cpp $(am__append_3)
+ SynthesisDBPlugin.cpp SyncContext.h SyncContext.cpp \
+ SyncConfig.h SyncConfig.cpp DevNullConfigNode.h \
+ MultiplexConfigNode.h MultiplexConfigNode.cpp \
+ FilterConfigNode.h FilterConfigNode.cpp SafeConfigNode.h \
+ SafeConfigNode.cpp PrefixConfigNode.h PrefixConfigNode.cpp \
+ FileConfigNode.h FileConfigNode.cpp FileConfigTree.h \
+ FileConfigTree.cpp TrackingSyncSource.h TrackingSyncSource.cpp \
+ $(am__append_3)
libsyncevolution_includedir = $(includedir)/syncevo
libsyncevolution_include_HEADERS = \
declarations.h \
DISTCLEANFILES = syncevolution.pc
EXTRA_DIST = syncevolution.pc.in installcheck-local.sh
libsyncevolution_la_SOURCES = $(SYNCEVOLUTION_SOURCES)
-libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ $(SYNTHESIS_LIBS) $(TRANSPORT_LIBS) @LIBS@ $(SYNCEVOLUTION_LDADD)
-libsyncevolution_la_CXXFLAGS = $(TRANSPORT_CFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(SYNTHESIS_CFLAGS)
-libsyncevolution_la_CPPFLAGS = $(AM_CPPFLAGS) -DTEMPLATE_DIR=\""$(datadir)/syncevolution/templates"\" -DLIBDIR=\""$(libdir)"\"
+nodist_libsyncevolution_la_SOURCES = SyncEvolutionXML.c
+CLEANFILES = SyncEvolutionXML.c
+libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ $(SYNTHESIS_LIBS) $(TRANSPORT_LIBS) @LIBS@ $(SYNCEVOLUTION_LDADD) $(NSS_LIBS)
+libsyncevolution_la_CXXFLAGS = $(TRANSPORT_CFLAGS) $(SYNCEVOLUTION_CXXFLAGS) $(SYNTHESIS_CFLAGS) $(NSS_CFLAGS)
+libsyncevolution_la_CPPFLAGS = $(AM_CPPFLAGS) \
+ -DXML_CONFIG_DIR=\""$(datadir)/syncevolution/xml"\" \
+ -DTEMPLATE_DIR=\""$(datadir)/syncevolution/templates"\" \
+ -DLIBDIR=\""$(libdir)"\"
+
libsyncevolution_la_DEPENDENCIES = $(SYNTHESIS_DEP)
@ENABLE_MODULES_FALSE@libsyncevolution_la_LDFLAGS = -static
@ENABLE_MODULES_TRUE@libsyncevolution_la_LDFLAGS =
-all: all-am
+
+# command which embeds its input lines into a C-style string that runs across multiple lines
+TO_C_STRING = sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/'
+all: all-recursive
.SUFFIXES:
.SUFFIXES: .c .cpp .lo .o .obj
rm -f "$(DESTDIR)$(libsyncevolution_includedir)/$$f"; \
done
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
mkid -fID $$unique
tags: TAGS
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
$$tags $$unique; \
fi
ctags: CTAGS
-CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|| exit 1; \
fi; \
done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
check-am: all-am
-check: check-am
+check: check-recursive
all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
-installdirs:
+installdirs: installdirs-recursive
+installdirs-am:
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(libsyncevolution_includedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-installcheck: installcheck-am
+installcheck: installcheck-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
mostlyclean-generic:
clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-clean: clean-am
+clean: clean-recursive
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
-distclean: distclean-am
+distclean: distclean-recursive
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
-dvi: dvi-am
+dvi: dvi-recursive
dvi-am:
-html: html-am
+html: html-recursive
-info: info-am
+info: info-recursive
info-am:
install-data-am: install-libsyncevolution_includeHEADERS \
install-pkgconfigDATA
-install-dvi: install-dvi-am
+install-dvi: install-dvi-recursive
install-exec-am: install-libLTLIBRARIES
-install-html: install-html-am
+install-html: install-html-recursive
-install-info: install-info-am
+install-info: install-info-recursive
install-man:
-install-pdf: install-pdf-am
+install-pdf: install-pdf-recursive
-install-ps: install-ps-am
+install-ps: install-ps-recursive
installcheck-am: installcheck-local
-maintainer-clean: maintainer-clean-am
+maintainer-clean: maintainer-clean-recursive
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
-mostlyclean: mostlyclean-am
+mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
-pdf: pdf-am
+pdf: pdf-recursive
pdf-am:
-ps: ps-am
+ps: ps-recursive
ps-am:
uninstall-libsyncevolution_includeHEADERS \
uninstall-pkgconfigDATA
-.MAKE: install-am install-strip
-
-.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
- clean-libLTLIBRARIES clean-libtool ctags distclean \
- distclean-compile distclean-generic distclean-libtool \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am \
- install-libLTLIBRARIES install-libsyncevolution_includeHEADERS \
- install-man install-pdf install-pdf-am install-pkgconfigDATA \
- install-ps install-ps-am install-strip installcheck \
- installcheck-am installcheck-local installdirs \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
- pdf pdf-am ps ps-am tags uninstall uninstall-am \
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+ install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags ctags-recursive \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES \
+ install-libsyncevolution_includeHEADERS install-man \
+ install-pdf install-pdf-am install-pkgconfigDATA install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installcheck-local installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-recursive uninstall uninstall-am \
uninstall-libLTLIBRARIES \
uninstall-libsyncevolution_includeHEADERS \
uninstall-pkgconfigDATA
-SyncEvolutionXML.c: $(srcdir)/../syncclient_sample_config.xml
- echo "const char *SyncEvolutionXML =" > $@
- sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/' $< >>$@
- echo ";" >>$@
+# Don't depend on specific XML files. Instead recreate
+# SyncEvolutionXML.c each time make is invoked (allows including new
+# fragments in the binary without rerunning configure).
+SyncEvolutionXML.c: GenSyncEvolutionXML
+.PHONY: GenSyncEvolutionXML
+GenSyncEvolutionXML:
+ echo "const char *SyncEvolutionXMLClient =" > SyncEvolutionXML.c.new
+ (cd $(srcdir)/configs && perl update-samples.pl syncevolution.xml client ) | \
+ perl -p -e 's;</datatypes>; <fieldlists/>\n <profiles/>\n <datatypedefs/>\n </datatypes>;' | \
+ $(TO_C_STRING) >>SyncEvolutionXML.c.new
+ echo ";" >>SyncEvolutionXML.c.new
+ echo "const char *SyncEvolutionXMLClientRules =" >> SyncEvolutionXML.c.new
+ (cd $(srcdir)/configs && cat remoterules/*.xml remoterules/client/*.xml) | $(TO_C_STRING) >>SyncEvolutionXML.c.new
+ echo ";" >>SyncEvolutionXML.c.new
+ if cmp SyncEvolutionXML.c SyncEvolutionXML.c.new >/dev/null; then rm SyncEvolutionXML.c.new; else mv SyncEvolutionXML.c.new SyncEvolutionXML.c; fi
# include boost in distribution
#dist-hook:
SE_BEGIN_CXX
-ObexTransportAgent::ObexTransportAgent (OBEX_TRANS_TYPE type) :
+ObexTransportAgent::ObexTransportAgent (OBEX_TRANS_TYPE type, GMainLoop *loop) :
m_status(INACTIVE),
m_transType(type),
+ m_context(g_main_context_ref(loop ?
+ g_main_loop_get_context(loop) :
+ g_main_context_default())),
m_address(""),
m_port(-1),
m_buffer(NULL),
m_obexReady = false;
if(m_transType == OBEX_BLUETOOTH) {
if(m_port == -1) {
+ EDSAbiWrapperInit();
+ // sdp_connect may be a pointer when EVOLUTION_COMPATIBILITY is enabled.
+ // Must check whether we really have an implementation of the sdp_ calls
+ // before using them.
+ if (!SyncEvoHaveLibbluetooth) {
+ SE_THROW_EXCEPTION (TransportException, "no suitable libbluetooth found, try setting Bluetooth channel manually (obex-bt://<mac>+<channel>)");
+ }
+
//use sdp to detect the appropriate channel
//Do not use BDADDR_ANY to avoid a warning
bdaddr_t bdaddr, anyaddr ={{0,0,0,0,0,0}};
cxxptr<Channel> channel;
while (!m_obexReady) {
- g_main_context_iteration (NULL, TRUE);
+ g_main_context_iteration (m_context, TRUE);
if (m_status == FAILED) {
if (m_obexEvent) {
obexEvent = m_obexEvent;
}
while (!m_obexReady) {
- g_main_context_iteration (NULL, FALSE);
+ g_main_context_iteration (m_context, TRUE);
if (m_status == FAILED) {
SE_THROW_EXCEPTION (TransportException,
"ObexTransprotAgent: Underlying transport error");
int seqSize = 0;
uint8_t dtdp;
-#ifdef HAVE_BLUEZ_BUFSIZE
- scanned = sdp_extract_seqtype(rsp, bufSize, &dtdp, &seqSize);
-#elif defined(HAVE_BLUEZ_SAFE)
+#if defined(HAVE_BLUEZ_SAFE) || defined(EVOLUTION_COMPATIBILITY)
scanned = sdp_extract_seqtype_safe(rsp, bufSize, &dtdp, &seqSize);
+#elif defined(HAVE_BLUEZ_BUFSIZE)
+ scanned = sdp_extract_seqtype(rsp, bufSize, &dtdp, &seqSize);
#else
scanned = sdp_extract_seqtype(rsp, &dtdp, &seqSize);
#endif
int recSize;
recSize = 0;
-#ifdef HAVE_BLUEZ_BUFSIZE
- rec = sdp_extract_pdu(rsp, bufSize, &recSize);
-#elif defined(HAVE_BLUEZ_SAFE)
+#if defined(HAVE_BLUEZ_SAFE) || defined(EVOLUTION_COMPATIBILITY)
rec = sdp_extract_pdu_safe(rsp, bufSize, &recSize);
+#elif defined(HAVE_BLUEZ_BUFSIZE)
+ rec = sdp_extract_pdu(rsp, bufSize, &recSize);
#else
rec = sdp_extract_pdu(rsp, &recSize);
#endif
m_connectStatus = END;
OBEX_TransportDisconnect (m_handle->get());
m_status = CLOSED;
- } else {
+ } else if (obex_rsp !=0) {
SE_LOG_ERROR (NULL, NULL, "ObexTransport Error %d", obex_rsp);
m_status = FAILED;
return;
*/
class ObexTransportAgent : public TransportAgent
{
+ class ContextUnref {
+ public:
+ static void unref(GMainContext *context) { g_main_context_unref(context); }
+ };
+
public:
enum OBEX_TRANS_TYPE{
OBEX_BLUETOOTH,
INVALID
};
- ObexTransportAgent(OBEX_TRANS_TYPE type);
+ /**
+ * @param loop the glib loop to use when waiting for IO;
+ * transport will increase the reference count;
+ * if NULL a new loop in the default context is used
+ */
+ ObexTransportAgent(OBEX_TRANS_TYPE type, GMainLoop *loop);
~ObexTransportAgent();
virtual void setURL (const std::string &url);
*/
OBEX_TRANS_TYPE m_transType;
+ /** context that needs to be kept alive while waiting for OBEX */
+ eptr<GMainContext, GMainContext, ContextUnref> m_context;
+
/* The address of the remote device
* macadd for Bluetooth; device name for usb; host name for
* tcp/ip
public:
static void unref(guint event) { g_source_remove(event); }
};
+class UnrefGString {
+ public:
+ static void unref(gchar *ptr) { g_free(ptr); }
+};
#endif // HAVE_GLIB
/**
#ifdef HAVE_GLIB
/** eptr for glib event handle */
typedef SmartPtr<guint, guint, UnrefGLibEvent> GLibEvent;
+typedef SmartPtr<gchar *, gchar *, UnrefGString> GString;
#endif
SE_END_CXX
SoupTransportAgent::SoupTransportAgent(GMainLoop *loop) :
m_session(soup_session_async_new()),
m_loop(loop ?
- loop :
+ g_main_loop_ref(loop) :
g_main_loop_new(NULL, TRUE),
"Soup main loop"),
m_status(INACTIVE),
public:
/**
* @param loop the glib loop to use when waiting for IO;
- * will be owned and unref'ed by the new instance;
+ * transport will increase the reference count;
* if NULL a new loop in the default context is used
*/
SoupTransportAgent(GMainLoop *loop = NULL);
string SyncConfig::normalizeConfigString(const string &config)
{
- string normal, context;
- normalizeConfigString(config, normal, context);
- return normal;
-}
-
-void SyncConfig::normalizeConfigString(const string &config, string &normal, string &context)
-{
- context = "";
- normal = config;
+ string normal = config;
boost::to_lower(normal);
BOOST_FOREACH(char &character, normal) {
if (!isprint(character) ||
}
}
if (boost::ends_with(normal, "@default")) {
- context = "default";
normal.resize(normal.size() - strlen("@default"));
} else if (boost::ends_with(normal, "@")) {
normal.resize(normal.size() - 1);
} else {
- // context specified?
size_t at = normal.rfind('@');
- if (at != normal.npos) {
- context = normal.substr(at + 1);
+ if (at == normal.npos) {
+ // No explicit context. Pick the first server which matches
+ // when ignoring their context. Peer list is sorted by name,
+ // therefore shorter config names (= without context) are
+ // found first, as intended.
+ BOOST_FOREACH(const StringPair &entry, getConfigs()) {
+ string entry_peer, entry_context;
+ splitConfigString(entry.first, entry_peer, entry_context);
+ if (normal == entry_peer) {
+ // found a matching, existing config, use it
+ normal = entry.first;
+ break;
+ }
+ }
}
}
+
if (normal.empty()) {
- // leave context empty, it wasn't set explicitly
+ // default context is meant with the empty string,
+ // better make that explicit
normal = "@default";
}
+
+ return normal;
}
void SyncConfig::splitConfigString(const string &config, string &peer, string &context)
string root;
- string context;
- normalizeConfigString(peer, m_peer, context);
- if (context.empty()) {
- // No explicit context. Pick the first server which matches
- // when ignoring their context. Peer list is sorted by name,
- // therefore shorter config names (= without context) are
- // found first, as intended.
- BOOST_FOREACH(const StringPair &entry, getConfigs()) {
- string entry_peer, entry_context;
- splitConfigString(entry.first, entry_peer, entry_context);
- if (m_peer == entry_peer) {
- // found a matching, existing config, use it
- m_peer = entry.first;
- break;
- }
- }
- }
+ m_peer = normalizeConfigString(peer);
// except for SHARED_LAYOUT (set below),
// everything is below the directory called like
} else {
TemplateConfig templateConf (sDir);
BOOST_FOREACH (const DeviceList::value_type &entry, peers){
- int rank = templateConf.metaMatch (entry.first, entry.second);
+ int rank = templateConf.metaMatch (entry.m_fingerprint, entry.m_matchMode);
if (fuzzyMatch){
if (rank > TemplateConfig::NO_MATCH) {
result.push_back (boost::shared_ptr<TemplateDescription>(
new TemplateDescription(templateConf.getName(),
- templateConf.getDescription(), rank, entry.first, sDir, templateConf.getFingerprint())));
+ templateConf.getDescription(), rank, entry.m_deviceId, entry.m_fingerprint, sDir, templateConf.getFingerprint())));
}
} else if (rank == TemplateConfig::BEST_MATCH){
result.push_back (boost::shared_ptr<TemplateDescription>(
new TemplateDescription(templateConf.getName(),
- templateConf.getDescription(), rank, entry.first, sDir, templateConf.getFingerprint())));
+ templateConf.getDescription(), rank, entry.m_deviceId, entry.m_fingerprint, sDir, templateConf.getFingerprint())));
break;
}
}
templateConfig = server;
} else {
SyncConfig::DeviceList devices;
- devices.push_back (std::make_pair(server, MATCH_ALL));
+ devices.push_back (DeviceDescription("", server, MATCH_ALL));
templateConfig = "";
TemplateList templates = matchPeerTemplates (devices, false);
if (!templates.empty()) {
boost::shared_ptr<PersistentSyncSourceConfig> source;
config->setDefaults(false);
- // The prefix is important: without it, myFUNAMBOL 6.x and 7.0 map
- // all SyncEvolution instances to the single phone that they support,
- // which leads to unwanted slow syncs when switching between multiple
- // instances.
- config->setDevID(string("sc-pim-") + UUID());
+ config->setDevID(string("syncevolution-") + UUID());
// create sync source configs and set non-default values
config->setSourceDefaults("addressbook", false);
static ConfigProperty syncPropSyncURL("syncURL",
"Identifies how to contact the peer,\n"
- "best explained with some examples.\n"
+ "best explained with some examples:\n"
"HTTP(S) SyncML servers:\n"
" http://my.funambol.com/sync\n"
" http://sync.scheduleworld.com/funambol/ds\n"
"the channel chosen automatically:\n"
" obex-bt://00:0A:94:03:F3:7E\n"
"If the automatism fails, the channel can also be specified:\n"
- " obex-bt://00:0A:94:03:F3:7E+16\n");
+ " obex-bt://00:0A:94:03:F3:7E+16\n"
+ "For peers contacting us via Bluetooth, the MAC address is\n"
+ "used to identify it before the sync starts. Multiple\n"
+ "urls can be specified in one syncURL property:\n"
+ " obex-bt://00:0A:94:03:F3:7E obex-bt://00:01:02:03:04:05\n"
+ "In the future this might be used to contact the peer\n"
+ "via one of several transports; right now, only the first\n"
+ "one is tried." // MB #9446
+ );
static ConfigProperty syncPropDevID("deviceId",
"The SyncML server gets this string and will use it to keep track of\n"
" this as 'user wants to start from scratch') => the sync would\n"
" recreate all the client's data, even if the user really wanted\n"
" to have it deleted, therefore slow sync is prevented\n"
- "Slow syncs are not yet detected when running as server and in the\n"
- "client when the server's anchor is wrong.\n"
- "This option is not enabled by default because it forces users\n"
- "to deal with slow syncs, which is a deviation from previous\n"
- "behavior.",
- "0");
+ "Slow syncs are not yet detected when running as server.\n",
+ "1");
static BoolConfigProperty syncPropUseProxy("useProxy",
"set to T to choose an HTTP proxy explicitly; otherwise the default\n"
"proxy settings of the underlying HTTP transport mechanism are used;\n"
"peer can be told to never sent items larger than a certain\n"
"threshold (maxObjSize). Presumably the peer has to truncate or\n"
"skip larger items. Sizes are specified as number of bytes.",
- "20000");
+ "150000");
static UIntConfigProperty syncPropMaxObjSize("maxObjSize", "", "4000000");
static BoolConfigProperty syncPropCompression("enableCompression", "enable compression of network traffic (not currently supported)");
syncPropProxyPassword.savePassword(ui, m_peer, *getNode(syncPropProxyPassword), "", boost::shared_ptr<FilterConfigNode>());
}
void SyncConfig::setProxyPassword(const string &value, bool temporarily) { m_cachedProxyPassword = ""; syncPropProxyPassword.setProperty(*getNode(syncPropProxyPassword), value, temporarily); }
-const char *SyncConfig::getSyncURL() const { return m_stringCache.getProperty(*getNode(syncPropSyncURL), syncPropSyncURL); }
+vector<string> SyncConfig::getSyncURL() const {
+ string s = m_stringCache.getProperty(*getNode(syncPropSyncURL), syncPropSyncURL);
+ vector<string> urls;
+ // workaround for g++ 4.3/4.4:
+ // http://stackoverflow.com/questions/1168525/c-gcc4-4-warning-array-subscript-is-above-array-bounds
+ static const string sep(" \t");
+ boost::split(urls, s, boost::is_any_of(sep));
+ return urls;
+}
void SyncConfig::setSyncURL(const string &value, bool temporarily) { syncPropSyncURL.setProperty(*getNode(syncPropSyncURL), value, temporarily); }
+void SyncConfig::setSyncURL(const vector<string> &value, bool temporarily) {
+ stringstream urls;
+ BOOST_FOREACH (string url, value) {
+ urls<<url<<" ";
+ }
+ return setSyncURL (urls.str(), temporarily);
+}
const char *SyncConfig::getClientAuthType() const { return m_stringCache.getProperty(*getNode(syncPropClientAuthType), syncPropClientAuthType); }
void SyncConfig::setClientAuthType(const string &value, bool temporarily) { syncPropClientAuthType.setProperty(*getNode(syncPropClientAuthType), value, temporarily); }
unsigned long SyncConfig::getMaxMsgSize() const { return syncPropMaxMsgSize.getPropertyValue(*getNode(syncPropMaxMsgSize)); }
" one-way-from-client = transmit changes from client\n"
" one-way-from-server = transmit changes from server\n"
" none (or disabled) = synchronization disabled",
- "two-way",
+ "disabled",
"",
Values() +
(Aliases("two-way")) +
static ConfigProperty sourcePropAdminData(SourceAdminDataName,
"used by the Synthesis library internally; do not modify");
+static IntConfigProperty sourcePropSynthesisID("synthesisID", "unique integer ID, necessary for libsynthesis", "0");
+
ConfigPropertyRegistry &SyncSourceConfig::getRegistry()
{
static ConfigPropertyRegistry registry;
registry.push_back(&sourcePropUser);
registry.push_back(&sourcePropPassword);
registry.push_back(&sourcePropAdminData);
+ registry.push_back(&sourcePropSynthesisID);
// obligatory source properties
SyncSourceConfig::m_sourcePropSync.setObligatory(true);
// non-shared properties (other hidden nodes don't
// exist at the moment)
sourcePropAdminData.setHidden(true);
+ sourcePropSynthesisID.setHidden(true);
// No global source properties. Does not make sense
// conceptually.
SourceType SyncSourceConfig::getSourceType() const { return getSourceType(m_nodes); }
void SyncSourceConfig::setSourceType(const string &value, bool temporarily) { sourcePropSourceType.setProperty(*getNode(sourcePropSourceType), value, temporarily); }
+const int SyncSourceConfig::getSynthesisID() const { return sourcePropSynthesisID.getPropertyValue(*getNode(sourcePropSynthesisID)); }
+void SyncSourceConfig::setSynthesisID(int value, bool temporarily) { sourcePropSynthesisID.setProperty(*getNode(sourcePropSynthesisID), value, temporarily); }
+
ConfigPasswordKey EvolutionPasswordConfigProperty::getPasswordKey(const string &descr,
const string &serverName,
FilterConfigNode &globalConfigNode,
private:
void normalize()
{
+ ScopedEnvChange xdg("XDG_CONFIG_HOME", "/dev/null");
+ ScopedEnvChange home("HOME", "/dev/null");
+
CPPUNIT_ASSERT_EQUAL(std::string("@default"),
SyncConfig::normalizeConfigString(""));
CPPUNIT_ASSERT_EQUAL(std::string("@default"),
// The matched percentage of the template, larger the better.
int m_rank;
+ //a unique identity of the device that the template is for, used by caller
+ std::string m_id;
+
// A string identify which fingerprint the template is matched with.
std::string m_fingerprint;
std::string m_matchedModel;
TemplateDescription (const std::string &name, const std::string &description,
- const int rank, const std::string &fingerprint, const std::string &path, const std::string &model)
+ const int rank, const std::string id, const std::string &fingerprint, const std::string &path, const std::string &model)
: m_name (name),
m_description (description),
m_rank (rank),
+ m_id (id),
m_fingerprint (fingerprint),
m_path (path),
m_matchedModel(model)
};
typedef list<boost::shared_ptr <TemplateDescription> > TemplateList;
- typedef list<std::pair <std::string, SyncConfig::MatchMode> > DeviceList;
+
+ struct DeviceDescription {
+ /** the id of the device */
+ std::string m_deviceId;
+ /** the finger print of the device used for matching templates */
+ std::string m_fingerprint;
+ /** match mode used for matching templates */
+ MatchMode m_matchMode;
+ DeviceDescription(const std::string &deviceId,
+ const std::string &fingerprint,
+ MatchMode mode)
+ :m_deviceId(deviceId), m_fingerprint(fingerprint), m_matchMode(mode)
+ {}
+ DeviceDescription() : m_matchMode(INVALID)
+ {}
+ };
+
+ typedef list<DeviceDescription> DeviceList;
/**
* returns list of servers in either the old (.sync4j) or
* - lower case
* - non-printable and unsafe characters (colon, slash, backslash)
* replaced by underscore
+ * - when no context specified: search for peer config first in @default,
+ * then also in other contexts in alphabetical order
* - @default stripped
* - empty string replaced with "@default"
*/
static string normalizeConfigString(const string &config);
/**
- * Normalize and in addition, set original context.
- *
- * @param config one of the various ways of selecting a configuration
- * (@default, scheduleworld, scheduleworld@foo, ...)
- * @retval normal normalized form of config string
- * @retval context empty if no specified, otherwise normalized value
- */
- static void normalizeConfigString(const string &config, string &normal, string &context);
-
- /**
* Split a config string (normalized or not) into the peer part
* (before final @) and the context (after that @, not including
* it), return "default" as context if not specified otherwise.
virtual void checkProxyPassword(ConfigUserInterface &ui);
virtual void saveProxyPassword(ConfigUserInterface &ui);
virtual void setProxyPassword(const string &value, bool temporarily = false);
- virtual const char* getSyncURL() const;
+ virtual vector<string> getSyncURL() const;
virtual void setSyncURL(const string &value, bool temporarily = false);
+ virtual void setSyncURL(const vector<string> &value, bool temporarily = false);
virtual const char* getClientAuthType() const;
virtual void setClientAuthType(const string &value, bool temporarily = false);
virtual unsigned long getMaxMsgSize() const;
/** same as SyncConfig::savePassword() */
virtual void savePassword(ConfigUserInterface &ui, const string &serverName, FilterConfigNode& globalConfigNode);
+ /** selects the backend database to use */
virtual const char *getDatabaseID() const;
virtual void setDatabaseID(const string &value, bool temporarily = false);
/**
+ * internal property: unique integer ID for the source, needed by Synthesis XML <dbtypeid>,
+ * zero if unset
+ */
+ virtual const int getSynthesisID() const;
+ virtual void setSynthesisID(int value, bool temporarily = false);
+
+ /**
* Returns the data source type configured as part of the given
* configuration; different SyncSources then check whether
* they support that type. This call has to work before instantiating
#include <boost/algorithm/string/join.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/split.hpp>
+#include <boost/bind.hpp>
#include <sys/stat.h>
#include <sys/wait.h>
#include <synthesis/SDK_util.h>
#include <synthesis/san.h>
+#include "test.h"
+
#include <syncevo/declarations.h>
SE_BEGIN_CXX
// internal prefix for backup directory name: "SyncEvolution-"
static const char* const DIR_PREFIX;
- /** set m_logdir and adapt m_prefix accordingly */
- void setLogdir(const string &logdir) {
- m_logdir = boost::trim_right_copy_if(logdir, boost::is_any_of("/"));
-
- // the config name has been normalized
- string peer = m_client.getConfigName();
-
- // escape "_" and "-" the peer name
- peer = escapePeer(peer);
-
- if (boost::iends_with(m_logdir, "syncevolution")) {
- // use just the server name as prefix
- m_prefix = peer;
- } else {
- // SyncEvolution-<server>-<yyyy>-<mm>-<dd>-<hh>-<mm>
- m_prefix = DIR_PREFIX;
- m_prefix += peer;
- }
- }
-
public:
LogDir(SyncContext &client) : m_client(client), m_parentLogger(LoggerBase::instance()), m_info(NULL), m_readonly(false), m_report(NULL)
{
rename(SubstEnvironment("${XDG_DATA_HOME}/applications/syncevolution").c_str(),
SubstEnvironment("${XDG_CACHE_HOME}/syncevolution").c_str());
- setLogdir(SubstEnvironment("${XDG_CACHE_HOME}/syncevolution"));
+ const char *path = m_client.getLogDir();
+ setLogdir(!path || !path[0] ?
+ "${XDG_CACHE_HOME}/syncevolution" :
+ path);
}
/**
- * Finds previous log directories. Reports errors via exceptions.
+ * Finds previous log directories for context. Reports errors via exceptions.
*
- * @param path path to configured backup directy, NULL if defaulting to /tmp, "none" if not creating log file
* @retval dirs vector of full path names, oldest first
*/
- void previousLogdirs(const char *path, vector<string> &dirs) {
- string logdir;
-
+ void previousLogdirs(vector<string> &dirs) {
dirs.clear();
- if (path && !strcasecmp(path, "none")) {
- return;
- } else {
- if (path && path[0]) {
- setLogdir(SubstEnvironment(path));
- }
- getLogdirs(dirs);
- }
+ getLogdirs(dirs);
}
/**
* @param path path to configured backup directy, NULL if defaulting to /tmp, "none" if not creating log file
* @return full path of previous log directory, empty string if not found
*/
- string previousLogdir(const char *path) throw() {
+ string previousLogdir() throw() {
try {
vector<string> dirs;
- previousLogdirs(path, dirs);
+ previousLogdirs(dirs);
return dirs.empty() ? "" : dirs.back();
} catch (...) {
Exception::handle();
}
/**
+ * Set log dir and base name used for searching and creating sessions.
+ * Default if not called is the getLogDir() value of the context.
+ *
+ * @param logdir "none" to disable sessions, NULL/"" for default, may contain ${}
+ * for environment variables
+ */
+ void setLogdir(const char *logdir) {
+ if (!logdir || !logdir[0]) {
+ return;
+ }
+ m_logdir = SubstEnvironment(logdir);
+ m_logdir = boost::trim_right_copy_if(m_logdir, boost::is_any_of("/"));
+ if (m_logdir == "none") {
+ return;
+ }
+
+ // the config name has been normalized
+ string peer = m_client.getConfigName();
+
+ // escape "_" and "-" the peer name
+ peer = escapePeer(peer);
+
+ if (boost::iends_with(m_logdir, "syncevolution")) {
+ // use just the server name as prefix
+ m_prefix = peer;
+ } else {
+ // SyncEvolution-<server>-<yyyy>-<mm>-<dd>-<hh>-<mm>
+ m_prefix = DIR_PREFIX;
+ m_prefix += peer;
+ }
+ }
+
+ /**
* access existing log directory to extract status information
*/
void openLogdir(const string &dir) {
// @param logLevel 0 = default, 1 = ERROR, 2 = INFO, 3 = DEBUG
// @param usePath write directly into path, don't create and manage subdirectories
// @param report record information about session here (may be NULL)
- // @param logname the basename to be used for logs, traditionally "client" for syncs
- void startSession(const char *path, int maxlogdirs, int logLevel, bool usePath, SyncReport *report, const string &logname) {
+ void startSession(const char *path, int maxlogdirs, int logLevel, bool usePath, SyncReport *report) {
m_maxlogdirs = maxlogdirs;
m_report = report;
m_logfile = "";
if (path && !strcasecmp(path, "none")) {
m_path = "";
} else {
- if (path && path[0]) {
- setLogdir(SubstEnvironment(path));
- }
-
+ setLogdir(path);
if (!usePath) {
// create unique directory name in the given directory
time_t ts = time(NULL);
<< setw(2) << tm->tm_mday << "-"
<< setw(2) << tm->tm_hour << "-"
<< setw(2) << tm->tm_min;
- // make sure no directory name has the same date time with others
- // even for different peers
- std::vector<string> dateTimes;
- if(isDir(m_logdir)) {
+ // If other sessions, regardless of which peer, have
+ // the same date and time, then append a sequence
+ // number to ensure correct sorting. Solve this by
+ // finding the maximum sequence number for any kind of
+ // date time. Backwards running clocks or changing the
+ // local time will still screw our ordering, though.
+ typedef std::map<string, int> SeqMap_t;
+ SeqMap_t dateTimes2Seq;
+ if (isDir(m_logdir)) {
ReadDir dir(m_logdir);
BOOST_FOREACH(const string &entry, dir) {
string dirPrefix, peerName, dateTime;
- if(parseDirName(entry, dirPrefix, peerName, dateTime)) {
- dateTimes.push_back(dateTime);
+ if (parseDirName(entry, dirPrefix, peerName, dateTime)) {
+ // dateTime = -2010-01-31-12-00[-rev]
+ size_t off = 0;
+ for (int i = 0; off != dateTime.npos && i < 5; i++) {
+ off = dateTime.find('-', off + 1);
+ }
+ int sequence;
+ if (off != dateTime.npos) {
+ sequence = atoi(dateTime.substr(off + 1).c_str());
+ dateTime.resize(off);
+ } else {
+ sequence = 0;
+ }
+ pair <SeqMap_t::iterator, bool> entry = dateTimes2Seq.insert(make_pair(dateTime, sequence));
+ if (sequence > entry.first->second) {
+ entry.first->second = sequence;
+ }
}
}
- sort(dateTimes.begin(), dateTimes.end());
}
- int seq = 0;
- while (true) {
- stringstream path;
- path << base.str();
- if (seq) {
- path << "-" << seq;
- }
- if (!binary_search(dateTimes.begin(), dateTimes.end(), path.str())) {
- m_path = m_logdir + "/";
- m_path += m_prefix;
- m_path += path.str();
- mkdir_p(m_path);
- break;
- } else {
- seq++;
- }
+ stringstream path;
+ path << base.str();
+ SeqMap_t::iterator it = dateTimes2Seq.find(path.str());
+ if (it != dateTimes2Seq.end()) {
+ path << "-" << it->second + 1;
}
+ m_path = m_logdir + "/";
+ m_path += m_prefix;
+ m_path += path.str();
+ mkdir_p(m_path);
} else {
m_path = m_logdir;
if (mkdir(m_path.c_str(), S_IRWXU) &&
m_info->setMode(false);
// Create a status.ini which contains an error.
// Will be overwritten later on, unless we crash.
- m_info->setProperty("status", "500");
+ m_info->setProperty("status", STATUS_DIED_PREMATURELY);
m_info->setProperty("error", "synchronization process died prematurely");
writeTimestamp("start", start);
}
return m_logfile;
}
- // remove oldest backup dirs if exceeding limit
+ /**
+ * remove backup dir(s) if exceeding limit
+ *
+ * Assign a priority to each session dir, with lower
+ * meaning "less important". Then sort by priority and (if
+ * equal) creation time (aka index) in ascending
+ * order. The sessions at the beginning of the sorted
+ * vector are then removed first.
+ *
+ * DUMPS = any kind of database dump was made
+ * ERROR = session failed
+ * CHANGES = local data modified since previous dump (based on dumps
+ * of the current peer, for simplicity reasons),
+ * dump created for the first time,
+ * changes made during sync (detected with dumps and statistics)
+ *
+ * The goal is to preserve as many database dumps as possible
+ * and ideally those where something happened.
+ *
+ * Some criteria veto the removal of a session:
+ * - it is the only one holding a dump of a specific source
+ * - it is the last session
+ */
void expire() {
if (m_logdir.size() && m_maxlogdirs > 0 ) {
vector<string> dirs;
getLogdirs(dirs);
+ /** stores priority and index in "dirs"; after sorting, delete from the start */
+ vector< pair<Priority, size_t> > victims;
+ /** maps from source name to list of information about dump, oldest first */
+ typedef map< string, list<DumpInfo> > Dumps_t;
+ Dumps_t dumps;
+ for (size_t i = 0;
+ i < dirs.size();
+ i++) {
+ bool changes = false;
+ bool havedumps = false;
+ bool errors = false;
+
+ LogDir logdir(m_client);
+ logdir.openLogdir(dirs[i]);
+ SyncReport report;
+ logdir.readReport(report);
+ SyncMLStatus status = report.getStatus();
+ if (status != STATUS_OK && status != STATUS_HTTP_OK) {
+ errors = true;
+ }
+ BOOST_FOREACH(SyncReport::SourceReport_t source, report) {
+ string &sourcename = source.first;
+ SyncSourceReport &sourcereport = source.second;
+ list<DumpInfo> &dumplist = dumps[sourcename];
+ if (sourcereport.m_backupBefore.isAvailable() ||
+ sourcereport.m_backupAfter.isAvailable()) {
+ // yes, we have backup dumps
+ havedumps = true;
+
+ DumpInfo info(i,
+ sourcereport.m_backupBefore.getNumItems(),
+ sourcereport.m_backupAfter.getNumItems());
+
+ // now check for changes, if none found yet
+ if (!changes) {
+ if (dumplist.empty()) {
+ // new backup dump
+ changes = true;
+ } else {
+ DumpInfo &previous = dumplist.back();
+ changes =
+ // item count changed -> items changed
+ previous.m_itemsDumpedAfter != info.m_itemsDumpedBefore ||
+ sourcereport.wasChanged(SyncSourceReport::ITEM_LOCAL) ||
+ sourcereport.wasChanged(SyncSourceReport::ITEM_REMOTE) ||
+ haveDifferentContent(sourcename,
+ dirs[previous.m_dirIndex], "after",
+ dirs[i], "before");
+ }
+ }
+
+ dumplist.push_back(info);
+ }
+ }
+ Priority pri =
+ havedumps ?
+ (changes ?
+ HAS_DUMPS_WITH_CHANGES :
+ errors ?
+ HAS_DUMPS_NO_CHANGES_WITH_ERRORS :
+ HAS_DUMPS_NO_CHANGES) :
+ (changes ?
+ NO_DUMPS_WITH_CHANGES :
+ errors ?
+ NO_DUMPS_WITH_ERRORS :
+ NO_DUMPS_NO_ERRORS);
+ victims.push_back(make_pair(pri, i));
+ }
+ sort(victims.begin(), victims.end());
+
int deleted = 0;
- for (vector<string>::iterator it = dirs.begin();
- it != dirs.end() && (int)dirs.size() - deleted > m_maxlogdirs;
- ++it, ++deleted) {
- string &path = *it;
- string msg = "removing " + path;
- SE_LOG_INFO(NULL, NULL, "%s", msg.c_str());
- rm_r(path);
+ for (size_t e = 0;
+ e < victims.size() && (int)dirs.size() - deleted > m_maxlogdirs;
+ ++e) {
+ size_t index = victims[e].second;
+ string &path = dirs[index];
+ // preserve latest session
+ if (index != dirs.size() - 1) {
+ bool mustkeep = false;
+ // also check whether it holds the only backup of a source
+ BOOST_FOREACH(Dumps_t::value_type dump, dumps) {
+ if (dump.second.size() == 1 &&
+ dump.second.front().m_dirIndex == index) {
+ mustkeep = true;
+ break;
+ }
+ }
+ if (!mustkeep) {
+ SE_LOG_DEBUG(NULL, NULL, "removing %s", path.c_str());
+ rm_r(path);
+ ++deleted;
+ }
+ }
}
}
}
return dateTime1 < dateTime2;
}
+ /**
+ * Compare two database dumps just based on their inodes.
+ * @return true if inodes differ
+ */
+ static bool haveDifferentContent(const string &sourceName,
+ const string &firstDir,
+ const string &firstSuffix,
+ const string &secondDir,
+ const string &secondSuffix)
+ {
+ string first = firstDir + "/" + sourceName + "." + firstSuffix;
+ string second = secondDir + "/" + sourceName + "." + secondSuffix;
+ ReadDir firstContent(first);
+ ReadDir secondContent(second);
+ set<ino_t> firstInodes;
+ BOOST_FOREACH(const string &name, firstContent) {
+ struct stat buf;
+ string fullpath = first + "/" + name;
+ if (stat(fullpath.c_str(), &buf)) {
+ SyncContext::throwError(fullpath, errno);
+ }
+ firstInodes.insert(buf.st_ino);
+ }
+ BOOST_FOREACH(const string &name, secondContent) {
+ struct stat buf;
+ string fullpath = second + "/" + name;
+ if (stat(fullpath.c_str(), &buf)) {
+ SyncContext::throwError(fullpath, errno);
+ }
+ set<ino_t>::iterator it = firstInodes.find(buf.st_ino);
+ if (it == firstInodes.end()) {
+ // second dir has different file
+ return true;
+ } else {
+ firstInodes.erase(it);
+ }
+ }
+ if (!firstInodes.empty()) {
+ // first dir has different file
+ return true;
+ }
+ // exact match of inodes
+ return false;
+ }
+
private:
+ enum Priority {
+ NO_DUMPS_NO_ERRORS,
+ NO_DUMPS_WITH_ERRORS,
+ NO_DUMPS_WITH_CHANGES,
+ HAS_DUMPS_NO_CHANGES,
+ HAS_DUMPS_NO_CHANGES_WITH_ERRORS,
+ HAS_DUMPS_WITH_CHANGES
+ };
+
+ struct DumpInfo {
+ size_t m_dirIndex;
+ int m_itemsDumpedBefore;
+ int m_itemsDumpedAfter;
+ DumpInfo(size_t dirIndex,
+ int itemsDumpedBefore,
+ int itemsDumpedAfter) :
+ m_dirIndex(dirIndex),
+ m_itemsDumpedBefore(itemsDumpedBefore),
+ m_itemsDumpedAfter(itemsDumpedAfter)
+ {}
+ };
+
/**
* extract backup directory name from a full backup path
* for example, a full path "/home/xxx/.cache/syncevolution/default/funambol-2009-12-08-14-05"
/**
* parse a directory name into dirPrefix(empty or DIR_PREFIX), peerName, dateTime.
+ * peerName must be unescaped by the caller to get the real string.
* If directory name is in the format of '[DIR_PREFIX]-peer[@context]-year-month-day-hour-min'
* then parsing is sucessful and these 3 strings are correctly set and true is returned.
* Otherwise, false is returned.
* logdir are returned.
*/
void getLogdirs(vector<string> &dirs) {
- if (!isDir(m_logdir)) {
+ if (m_logdir != "none" && !isDir(m_logdir)) {
return;
}
string peer = m_client.getConfigName();
} else if(peerName.empty()) {
// if no peer name and only context, match for all logs under the given context
string tmpName, tmpContext;
- SyncConfig::splitConfigString(tmpPeer, tmpName, tmpContext);
+ SyncConfig::splitConfigString(unescapePeer(tmpPeer), tmpName, tmpContext);
if( context == tmpContext && boost::starts_with(m_prefix, tmpDirPrefix)) {
dirs.push_back(m_logdir + "/" + entry);
}
const char* const LogDir::DIR_PREFIX = "SyncEvolution-";
-// this class owns the sync sources and (together with
-// a logdir) handles writing of per-sync files as well
-// as the final report
-// It also handles the virtual syncsources that is a combination of several
-// real syncsources.
-class SourceList : public vector<SyncSource *> {
+/**
+ * This class owns the sync sources. For historic reasons (required
+ * by Funambol) SyncSource instances are stored as plain pointers
+ * deleted by this class. Virtual sync sources were added later
+ * and are stored as shared pointers which are freed automatically.
+ * It is possible to iterate over the two classes of sources
+ * separately.
+ *
+ * The SourceList ensures that all sources (normal and virtual) have
+ * a valid and unique integer ID as needed for Synthesis. Traditionally
+ * this used to be a simple hash of the source name (which is unique
+ * by design), without checking for hash collisions. Now the ID is assigned
+ * the first time a source is added here and doesn't have one yet.
+ * For backward compatibility (the ID is stored in the .synthesis dir),
+ * the same Hash() value is tested first. Assuming that there were no
+ * hash conflicts, the same IDs will be generated as before.
+ *
+ * Together with a logdir, the SourceList
+ * handles writing of per-sync files as well as the final report.
+ * It is not stateless. The expectation is that it is instantiated
+ * together with a SyncContext for one particular operation (sync
+ * session, status check, restore). In contrast to a SyncContext,
+ * this class has to be recreated for another operation.
+ *
+ * When running as client, only the active sources get added. They can
+ * be dumped one after the other before running a sync.
+ *
+ * As a server, all sources get added, regardless whether they are
+ * active. This implies that at least their "type" must be valid. Then
+ * later when a client really starts using them, they are opened() and
+ * database dumps are made.
+ *
+ * Virtual datastores are stored here when they get initialized
+ * together with the normal sources by the user of SourceList.
+ *
+ *
+ */
+class SourceList : private vector<SyncSource *> {
+ typedef vector<SyncSource *> inherited;
+
public:
enum LogLevel {
LOGGING_QUIET, /**< avoid all extra output */
LOGGING_FULL /**< everything */
};
- struct SourceConfigSpecials{
- bool m_forceSlow;
- string m_alias;
- SourceConfigSpecials ():
- m_forceSlow(false),
- m_alias("")
- {
- }
- };
+ typedef std::vector< boost::shared_ptr<VirtualSyncSource> > VirtualSyncSources_t;
+
+ /** reading our set of virtual sources is okay, modifying it is not */
+ const VirtualSyncSources_t &getVirtualSources() { return m_virtualSources; }
+ void addSource(const boost::shared_ptr<VirtualSyncSource> &source) { checkSource(source.get()); m_virtualSources.push_back(source); }
+
+ using inherited::iterator;
+ using inherited::const_iterator;
+ using inherited::empty;
+ using inherited::begin;
+ using inherited::end;
+ using inherited::rbegin;
+ using inherited::rend;
+
+ /** transfers ownership (historic reasons for storing plain pointer...) */
+ void addSource(cxxptr<SyncSource> &source) { checkSource(source); push_back(source.release()); }
- std::vector<boost::shared_ptr<VirtualSyncSource> >m_virtualDS; /**All configured virtual datastores*/
- std::map<std::string, SourceConfigSpecials > m_configSpecials; /*Indicating whether the corresponding sync source is forced slow*/
private:
+ VirtualSyncSources_t m_virtualSources; /**< all configured virtual data sources (aka Synthesis <superdatastore>) */
LogDir m_logdir; /**< our logging directory */
SyncContext &m_client; /**< the context in which we were instantiated */
- bool m_prepared; /**< remember whether syncPrepare() dumped databases successfully */
+ set<string> m_prepared; /**< remember for which source we dumped databases successfully */
+ string m_intro; /**< remembers the dumpLocalChanges() intro and only prints it again
+ when different from last dumpLocalChanges() call */
bool m_doLogging; /**< true iff the normal logdir handling is enabled
(creating and expiring directoties, before/after comparison) */
bool m_reportTodo; /**< true if syncDone() shall print a final report */
source.getName() + "." + suffix;
}
+ /** ensure that Synthesis ID is set and unique */
+ void checkSource(SyncSource *source) {
+ if (source->getSynthesisID()) {
+ return;
+ }
+ int id = Hash(source->getName()) % INT_MAX;
+ while (true) {
+ // avoid negative values
+ if (id < 0) {
+ id = -id;
+ }
+ // avoid zero, it means unset
+ if (!id) {
+ id = 1;
+ }
+ // check for collisions
+ bool collision = false;
+ BOOST_FOREACH(const string &other, m_client.getSyncSources()) {
+ boost::shared_ptr<PersistentSyncSourceConfig> sc(m_client.getSyncSourceConfig(other));
+ int other_id = sc->getSynthesisID();
+ if (other_id == id) {
+ ++id;
+ collision = true;
+ break;
+ }
+ }
+ if (!collision) {
+ source->setSynthesisID(id);
+ return;
+ }
+ }
+ }
+
public:
LogLevel getLogLevel() const { return m_logLevel; }
void setLogLevel(LogLevel logLevel) { m_logLevel = logLevel; }
/**
- * dump into files with a certain suffix,
- * optionally store report in member of SyncSourceReport
+ * Dump into files with a certain suffix, optionally store report
+ * in member of SyncSourceReport. Remembers which sources were
+ * dumped before a sync and only dumps those again afterward.
+ *
+ * @param suffix "before/after/current" - before sync, after sync, during status check
+ * @param excludeSource when not empty, only dump that source
*/
void dumpDatabases(const string &suffix,
- BackupReport SyncSourceReport::*report) {
+ BackupReport SyncSourceReport::*report,
+ const string &excludeSource = "") {
+ // Identify all logdirs of current context, of any peer. Used
+ // to search for previous backups of each source, if
+ // necessary.
+ string peer = m_client.getConfigName();
+ string peerName, contextName;
+ SyncConfig::splitConfigString(peer, peerName, contextName);
+ SyncContext context(string("@") + contextName);
+ LogDir logdir(context);
+ vector<string> dirs;
+ logdir.previousLogdirs(dirs);
+
BOOST_FOREACH(SyncSource *source, *this) {
+ if ((!excludeSource.empty() && excludeSource != source->getName()) ||
+ (suffix == "after" && m_prepared.find(source->getName()) == m_prepared.end())) {
+ continue;
+ }
+
string dir = databaseName(*source, suffix);
boost::shared_ptr<ConfigNode> node = ConfigNode::createFileNode(dir + ".ini");
SE_LOG_DEBUG(NULL, NULL, "creating %s", dir.c_str());
rm_r(dir);
- mkdir_p(dir);
BackupReport dummy;
if (source->getOperations().m_backupData) {
- source->getOperations().m_backupData(dir, *node,
+ SyncSource::Operations::ConstBackupInfo oldBackup;
+ // Now look for a backup of the current source,
+ // starting with the most recent one.
+ for (vector<string>::const_reverse_iterator it = dirs.rbegin();
+ it != dirs.rend();
+ ++it) {
+ const string &sessiondir = *it;
+ string oldBackupDir;
+ SyncSource::Operations::BackupInfo::Mode mode =
+ SyncSource::Operations::BackupInfo::BACKUP_AFTER;
+ oldBackupDir = databaseName(*source, "after", sessiondir);
+ if (!isDir(oldBackupDir)) {
+ mode = SyncSource::Operations::BackupInfo::BACKUP_BEFORE;
+ oldBackupDir = databaseName(*source, "before", sessiondir);
+ if (!isDir(oldBackupDir)) {
+ // try next session
+ continue;
+ }
+ }
+
+ oldBackup.m_mode = mode;
+ oldBackup.m_dirname = oldBackupDir;
+ oldBackup.m_node = ConfigNode::createFileNode(oldBackupDir + ".ini");
+ break;
+ }
+ mkdir_p(dir);
+ SyncSource::Operations::BackupInfo newBackup(suffix == "before" ?
+ SyncSource::Operations::BackupInfo::BACKUP_BEFORE :
+ suffix == "after" ?
+ SyncSource::Operations::BackupInfo::BACKUP_AFTER :
+ SyncSource::Operations::BackupInfo::BACKUP_OTHER,
+ dir, node);
+ source->getOperations().m_backupData(oldBackup, newBackup,
report ? source->*report : dummy);
SE_LOG_DEBUG(NULL, NULL, "%s created", dir.c_str());
+
+ // remember that we have dumped at the beginning of a sync
+ if (suffix == "before") {
+ m_prepared.insert(source->getName());
+ }
}
}
}
SyncContext::throwError(dir + ": no such database backup found");
}
if (source.getOperations().m_restoreData) {
- source.getOperations().m_restoreData(dir, *node, dryrun, report);
+ source.getOperations().m_restoreData(SyncSource::Operations::ConstBackupInfo(SyncSource::Operations::BackupInfo::BACKUP_OTHER, dir, node),
+ dryrun, report);
}
}
SourceList(SyncContext &client, bool doLogging) :
m_logdir(client),
m_client(client),
- m_prepared(false),
m_doLogging(doLogging),
m_reportTodo(true),
m_logLevel(LOGGING_FULL)
}
// call as soon as logdir settings are known
- void startSession(const char *logDirPath, int maxlogdirs, int logLevel, SyncReport *report,
- const string &logname) {
- m_previousLogdir = m_logdir.previousLogdir(logDirPath);
+ void startSession(const char *logDirPath, int maxlogdirs, int logLevel, SyncReport *report) {
+ m_logdir.setLogdir(logDirPath);
+ m_previousLogdir = m_logdir.previousLogdir();
if (m_doLogging) {
- m_logdir.startSession(logDirPath, maxlogdirs, logLevel, false, report, logname);
+ m_logdir.startSession(logDirPath, maxlogdirs, logLevel, false, report);
} else {
// Run debug session without paying attention to
// the normal logdir handling. The log level here
// refers to stdout. The log file will be as complete
// as possible.
- m_logdir.startSession(logDirPath, 0, 1, true, report, logname);
+ m_logdir.startSession(logDirPath, 0, 1, true, report);
}
}
* If possible (directory to compare against available) and enabled,
* then dump changes applied locally.
*
+ * @param oldSession directory to compare against; "" searches in sessions of current peer
+ * as selected by context for the lastest one involving each source
* @param oldSuffix suffix of old database dump: usually "after"
* @param currentSuffix the current database dump suffix: "current"
* when not doing a sync, otherwise "before"
+ * @param excludeSource when not empty, only dump that source
*/
- bool dumpLocalChanges(const string &oldDir,
+ bool dumpLocalChanges(const string &oldSession,
const string &oldSuffix, const string &newSuffix,
- const string &intro = "Local data changes to be applied to server during synchronization:\n",
+ const string &excludeSource,
+ const string &intro = "Local data changes to be applied remotely during synchronization:\n",
const string &config = "CLIENT_TEST_LEFT_NAME='after last sync' CLIENT_TEST_RIGHT_NAME='current data' CLIENT_TEST_REMOVED='removed since last sync' CLIENT_TEST_ADDED='added since last sync'") {
- if (m_logLevel <= LOGGING_SUMMARY || oldDir.empty()) {
+ if (m_logLevel <= LOGGING_SUMMARY) {
return false;
}
- cout << intro;
+ vector<string> dirs;
+ if (oldSession.empty()) {
+ m_logdir.previousLogdirs(dirs);
+ }
+
BOOST_FOREACH(SyncSource *source, *this) {
- string oldFile = databaseName(*source, oldSuffix, oldDir);
- string newFile = databaseName(*source, newSuffix);
+ if ((!excludeSource.empty() && excludeSource != source->getName()) ||
+ (newSuffix == "after" && m_prepared.find(source->getName()) == m_prepared.end())) {
+ continue;
+ }
+
+ // dump only if not done before or changed
+ if (m_intro != intro) {
+ cout << intro;
+ m_intro = intro;
+ }
+
+ string oldDir;
+ if (oldSession.empty()) {
+ // Now look for the latest session involving the current source,
+ // starting with the most recent one.
+ for (vector<string>::const_reverse_iterator it = dirs.rbegin();
+ it != dirs.rend();
+ ++it) {
+ const string &sessiondir = *it;
+ LogDir oldsession(m_client);
+ oldsession.openLogdir(sessiondir);
+ SyncReport report;
+ oldsession.readReport(report);
+ if (report.find(source->getName()) != report.end()) {
+ // source was active in that session, use dump
+ // made there
+ oldDir = databaseName(*source, oldSuffix, sessiondir);
+ break;
+ }
+ }
+ } else {
+ oldDir = databaseName(*source, oldSuffix, oldSession);
+ }
+ string newDir = databaseName(*source, newSuffix);
cout << "*** " << source->getName() << " ***\n" << flush;
string cmd = string("env CLIENT_TEST_COMPARISON_FAILED=10 " + config + " synccompare 2>/dev/null '" ) +
- oldFile + "' '" + newFile + "'";
+ oldDir + "' '" + newDir + "'";
int ret = system(cmd.c_str());
switch (ret == -1 ? ret : WEXITSTATUS(ret)) {
case 0:
// call when all sync sources are ready to dump
// pre-sync databases
- void syncPrepare() {
+ // @param excludeSource when non-empty, limit preparation to that source
+ void syncPrepare(const string &excludeSource = "") {
if (m_logdir.getLogfile().size() &&
m_doLogging) {
// dump initial databases
- dumpDatabases("before", &SyncSourceReport::m_backupBefore);
+ dumpDatabases("before", &SyncSourceReport::m_backupBefore, excludeSource);
// compare against the old "after" database dump
- dumpLocalChanges(getPrevLogdir(), "after", "before");
-
- m_prepared = true;
+ dumpLocalChanges("", "after", "before", excludeSource);
}
}
if (m_doLogging) {
// dump database after sync, but not if already dumping it at the beginning didn't complete
- if (m_reportTodo && m_prepared) {
+ if (m_reportTodo && !m_prepared.empty()) {
try {
dumpDatabases("after", &SyncSourceReport::m_backupAfter);
} catch (...) {
Exception::handle();
- m_prepared = false;
+ // not exactly sure what the problem was, but don't
+ // try it again
+ m_prepared.clear();
}
if (report) {
// update report with more recent information about m_backupAfter
}
// compare databases?
- if (m_logLevel > LOGGING_SUMMARY && m_prepared) {
- cout << "\nChanges applied to client during synchronization:\n";
- BOOST_FOREACH(SyncSource *source, *this) {
- cout << "*** " << source->getName() << " ***\n" << flush;
-
- string before = databaseName(*source, "before");
- string after = databaseName(*source, "after");
- string cmd = string("synccompare '" ) +
- before + "' '" + after +
- "' && echo 'no changes'";
- if (system(cmd.c_str())) {
- // ignore error
- }
- }
- cout << "\n";
- }
+ dumpLocalChanges(m_logdir.getLogdir(),
+ "before", "after", "",
+ "\nData modified locally during synchronization:\n",
+ "CLIENT_TEST_LEFT_NAME='before sync' CLIENT_TEST_RIGHT_NAME='after sync' CLIENT_TEST_REMOVED='removed during sync' CLIENT_TEST_ADDED='added during sync'");
- if (status == STATUS_OK) {
- m_logdir.expire();
- }
+ m_logdir.expire();
}
}
}
}
}
- /** find sync source by name */
+ /** find sync source by name (both normal and virtual sources) */
SyncSource *operator [] (const string &name) {
BOOST_FOREACH(SyncSource *source, *this) {
if (name == source->getName()) {
return source;
}
}
+ BOOST_FOREACH(boost::shared_ptr<VirtualSyncSource> &source, m_virtualSources) {
+ if (name == source->getName()) {
+ return source.get();
+ }
+ }
return NULL;
}
- /** find by index */
- SyncSource *operator [] (int index) { return vector<SyncSource *>::operator [] (index); }
+ /** find by XML <dbtypeid> (the ID used by Synthesis to identify sources in progress events) */
+ SyncSource *lookupBySynthesisID(int synthesisid) {
+ BOOST_FOREACH(SyncSource *source, *this) {
+ if (source->getSynthesisID() == synthesisid) {
+ return source;
+ }
+ }
+ BOOST_FOREACH(boost::shared_ptr<VirtualSyncSource> &source, m_virtualSources) {
+ if (source->getSynthesisID() == synthesisid) {
+ return source.get();
+ }
+ }
+ return NULL;
+ }
};
void unref(SourceList *sourceList)
}
}
-boost::shared_ptr<TransportAgent> SyncContext::createTransportAgent()
+string SyncContext::getUsedSyncURL() {
+ vector<string> urls = getSyncURL();
+ BOOST_FOREACH (string url, urls) {
+ if (boost::starts_with(url, "http://") ||
+ boost::starts_with(url, "https://")) {
+#ifdef ENABLE_LIBSOUP
+ return url;
+#elif defined(ENABLE_LIBCURL)
+ return url;
+#endif
+ } else if (url.find("obex-bt://") ==0) {
+#ifdef ENABLE_BLUETOOTH
+ return url;
+#endif
+ }
+ }
+ return "";
+}
+
+boost::shared_ptr<TransportAgent> SyncContext::createTransportAgent(void *gmainloop)
{
- std::string url = getSyncURL();
+ string url = getUsedSyncURL();
if (boost::starts_with(url, "http://") ||
boost::starts_with(url, "https://")) {
#ifdef ENABLE_LIBSOUP
- boost::shared_ptr<SoupTransportAgent> agent(new SoupTransportAgent());
+
+ boost::shared_ptr<SoupTransportAgent> agent(new SoupTransportAgent(static_cast<GMainLoop *>(gmainloop)));
agent->setConfig(*this);
return agent;
#elif defined(ENABLE_LIBCURL)
- boost::shared_ptr<CurlTransportAgent> agent(new CurlTransportAgent());
- agent->setConfig(*this);
- return agent;
+ if (!gmainloop) {
+ boost::shared_ptr<CurlTransportAgent> agent(new CurlTransportAgent());
+ agent->setConfig(*this);
+ return agent;
+ }
#endif
} else if (url.find("obex-bt://") ==0) {
#ifdef ENABLE_BLUETOOTH
std::string btUrl = url.substr (strlen ("obex-bt://"), std::string::npos);
- boost::shared_ptr<ObexTransportAgent> agent(new ObexTransportAgent(ObexTransportAgent::OBEX_BLUETOOTH));
+ boost::shared_ptr<ObexTransportAgent> agent(new ObexTransportAgent(ObexTransportAgent::OBEX_BLUETOOTH,
+ static_cast<GMainLoop *>(gmainloop)));
agent->setURL (btUrl);
agent->connect();
return agent;
case sysync::PEV_PREPARING:
/* preparing (e.g. preflight in some clients), extra1=progress, extra2=total */
/* extra2 might be zero */
- if (source.getFinalSyncMode() == SYNC_NONE) {
+ /*
+ * At the moment, preparing items doesn't do any real work.
+ * Printing this progress just increases the output and slows
+ * us down. Disabled.
+ */
+ if (true || source.getFinalSyncMode() == SYNC_NONE) {
// not active, suppress output
} else if (extra2) {
SE_LOG_INFO(NULL, NULL, "%s: preparing %d/%d",
break;
case 0:
break;
+ case sysync::LOCERR_DATASTORE_ABORT:
+ // this can mean only one thing in SyncEvolution: unexpected slow sync
+ extra1 = STATUS_UNEXPECTED_SLOW_SYNC;
+ // no break!
default:
// Printing unknown status codes here is of somewhat questionable value,
// because even "good" sources will get a bad status when the overall
SyncSource *SyncContext::findSource(const char *name)
{
- return m_sourceListPtr ? (*m_sourceListPtr)[name] : NULL;
+ if (!m_sourceListPtr) {
+ return NULL;
+ }
+ const char *realname = strrchr(name, m_findSourceSeparator);
+ if (realname) {
+ realname++;
+ } else {
+ realname = name;
+ }
+ return (*m_sourceListPtr)[realname];
}
SyncContext *SyncContext::findContext(const char *sessionName)
void SyncContext::initSources(SourceList &sourceList)
{
list<string> configuredSources = getSyncSources();
+ map<string, string> subSources;
// Phase 1, check all virtual sync soruces
BOOST_FOREACH(const string &name, configuredSources) {
//sub syncsources here
SyncSourceParams params(name, source);
boost::shared_ptr<VirtualSyncSource> vSource = boost::shared_ptr<VirtualSyncSource> (new VirtualSyncSource (params));
- std::string evoSyncSource = vSource->getDatabaseID();
- bool valid = true;
- std::vector<std::string> mappedSources = unescapeJoinedString (evoSyncSource, ',');
+ std::vector<std::string> mappedSources = vSource->getMappedSources();
BOOST_FOREACH (std::string source, mappedSources) {
//check whether the mapped source is really available
boost::shared_ptr<PersistentSyncSourceConfig> source_config
= getSyncSourceConfig(source);
if (!source_config || !source_config->exists()) {
- SE_LOG_ERROR (NULL, NULL,
- "Virtual datasource %s referenced a non-existed datasource %s, check your configuration!",
- vSource->getName(), source.c_str());
- valid = false;
- break;
+ throwError(StringPrintf("Virtual data source \"%s\" references a nonexistent datasource \"%s\".", name.c_str(), source.c_str()));
}
- }
- if (valid) {
- FilterConfigNode::ConfigFilter vFilter;
- vFilter["sync"] = sync;
- vFilter["uri"] = sc->getURI();
- BOOST_FOREACH (std::string source, mappedSources) {
- setConfigFilter (false, source, vFilter);
+ pair< map<string, string>::iterator, bool > res = subSources.insert(make_pair(source, name));
+ if (!res.second) {
+ throwError(StringPrintf("Data source \"%s\" included in the virtual sources \"%s\" and \"%s\". It can only be included in one virtual source at a time.",
+ source.c_str(), res.first->second.c_str(), name.c_str()));
}
+
+ }
+ FilterConfigNode::ConfigFilter vFilter;
+ vFilter["sync"] = sync;
+ if (!m_serverMode) {
+ // must set special URI for clients so that
+ // engine knows about superdatastore and its
+ // URI
+ vFilter["uri"] = string("<") + vSource->getName() + ">" + vSource->getURI();
}
- sourceList.m_virtualDS.push_back (vSource);
+ BOOST_FOREACH (std::string source, mappedSources) {
+ setConfigFilter (false, source, vFilter);
+ }
+ sourceList.addSource(vSource);
}
}
}
bool enabled = sync != "disabled";
if (enabled) {
if (sourceType.m_backend != "virtual") {
- string url = getSyncURL();
SyncSourceParams params(name,
source);
- SyncSource *syncSource =
- SyncSource::createSource(params);
+ cxxptr<SyncSource> syncSource(SyncSource::createSource(params));
if (!syncSource) {
throwError(name + ": type unknown" );
}
- sourceList.push_back(syncSource);
+ if (subSources.find(name) != subSources.end()) {
+ syncSource->recordVirtualSource(subSources[name]);
+ }
+ sourceList.addSource(syncSource);
}
- sourceList.m_configSpecials[name].m_alias = sc->getURI();
} else {
// the Synthesis engine is never going to see this source,
// therefore we have to mark it as 100% complete and
}
}
+void SyncContext::startSourceAccess(SyncSource *source)
+{
+ if (m_serverMode) {
+ // source is active in sync, now open it
+ source->open();
+ }
+ // database dumping is delayed in both client and server
+ m_sourceListPtr->syncPrepare(source->getName());
+}
+
bool SyncContext::transport_cb (void *udata)
{
unsigned int interval = reinterpret_cast<uintptr_t>(udata);
seconds);
}
-// XML configuration converted to C string constant
+// XML configuration converted to C string constants
extern "C" {
- extern const char *SyncEvolutionXML;
+ // including all known fragments for a client
+ extern const char *SyncEvolutionXMLClient;
+ // the remote rules for a client
+ extern const char *SyncEvolutionXMLClientRules;
}
void SyncContext::setSyncModes(const std::vector<SyncSource *> &sources,
}
}
-void SyncContext::getConfigTemplateXML(string &xml, string &configname)
+/**
+ * helper class which scans directories for
+ * XML config files
+ */
+class XMLFiles
{
- try {
- configname = "syncclient_sample_config.xml";
- if (ReadFile(configname, xml)) {
- return;
- }
- } catch (...) {
- Exception::handle();
- }
+public:
+ enum Category {
+ MAIN, /**< files directly under searched directories */
+ DATATYPES, /**< inside datatypes and datatypes/<mode> */
+ SCRIPTING, /**< inside scripting and scripting/<mode> */
+ REMOTERULES, /**< inside remoterules and remoterules/<mode> */
+ MAX_CATEGORY
+ };
+
+ /** search file system for XML config fragments */
+ void scan(const string &mode);
+ /** datatypes, scripts and rules concatenated, empty if none found */
+ string get(Category category);
+ /** main file, typically "syncevolution.xml", empty if not found */
+ string get(const string &file);
+
+ static const string m_syncevolutionXML;
+
+private:
+ /* base name as sort key + full file path, iterating is done in lexical order */
+ StringMap m_files[MAX_CATEGORY];
+
+ /**
+ * scan a specific directory for main files directly inside it
+ * and inside datatypes, scripting, remoterules;
+ * it is not an error when it does not exist or is not a directory
+ */
+ void scanRoot(const string &mode, const string &dir);
/**
- * @TODO read from config directory
+ * scan a datatypes/scripting/remoterules sub directory,
+ * including the <mode> sub-directory
+ */
+ void scanFragments(const string &mode, const string &dir, Category category);
+
+ /**
+ * add all .xml files to the right hash, overwriting old entries
+ */
+ void addFragments(const string &dir, Category category);
+};
+
+const string XMLFiles::m_syncevolutionXML("syncevolution.xml");
+
+void XMLFiles::scan(const string &mode)
+{
+ const char *dir = getenv("SYNCEVOLUTION_XML_CONFIG_DIR");
+ /*
+ * read either one or the other, so that testing can run without
+ * accidentally reading installed files
*/
+ if (dir) {
+ scanRoot(mode, dir);
+ } else {
+ scanRoot(mode, XML_CONFIG_DIR);
+ scanRoot(mode, SubstEnvironment("${XDG_CONFIG_HOME}/syncevolution-xml"));
+ }
+}
+
+void XMLFiles::scanRoot(const string &mode, const string &dir)
+{
+ addFragments(dir, MAIN);
+ scanFragments(mode, dir + "/scripting", SCRIPTING);
+ scanFragments(mode, dir + "/datatypes", DATATYPES);
+ scanFragments(mode, dir + "/remoterules", REMOTERULES);
+}
+
+void XMLFiles::scanFragments(const string &mode, const string &dir, Category category)
+{
+ addFragments(dir, category);
+ addFragments(dir + "/" + mode, category);
+}
- configname = "builtin XML configuration";
- xml = SyncEvolutionXML;
+void XMLFiles::addFragments(const string &dir, Category category)
+{
+ if (!isDir(dir)) {
+ return;
+ }
+ ReadDir content(dir);
+ BOOST_FOREACH(const string &file, content) {
+ if (boost::ends_with(file, ".xml")) {
+ m_files[category][file] = dir + "/" + file;
+ }
+ }
+}
+
+string XMLFiles::get(Category category)
+{
+ string res;
+
+ BOOST_FOREACH(const StringPair &entry, m_files[category]) {
+ string content;
+ ReadFile(entry.second, content);
+ res += content;
+ }
+ return res;
+}
+
+string XMLFiles::get(const string &file)
+{
+ string res;
+ StringMap::const_iterator entry = m_files[MAIN].find(file);
+ if (entry != m_files[MAIN].end()) {
+ ReadFile(entry->second, res);
+ }
+ return res;
}
static void substTag(string &xml, const string &tagname, const string &replacement, bool replaceElement = false)
substTag(xml, tagname, str.str(), replaceElement);
}
+void SyncContext::getConfigTemplateXML(const string &mode,
+ string &xml,
+ string &rules,
+ string &configname)
+{
+ XMLFiles files;
+
+ files.scan(mode);
+ xml = files.get(files.m_syncevolutionXML);
+ if (xml.empty()) {
+ if (mode != "client") {
+ SE_THROW(files.m_syncevolutionXML + " not found");
+ }
+ configname = "builtin XML configuration";
+ xml = SyncEvolutionXMLClient;
+ rules = SyncEvolutionXMLClientRules;
+ } else {
+ configname = "XML configuration files";
+ rules = files.get(XMLFiles::REMOTERULES);
+ substTag(xml, "datatypes",
+ files.get(XMLFiles::DATATYPES) +
+ " <fieldlists/>\n <profiles/>\n <datatypedefs/>\n");
+ substTag(xml, "scripting", files.get(XMLFiles::SCRIPTING));
+ }
+}
+
void SyncContext::getConfigXML(string &xml, string &configname)
{
- getConfigTemplateXML(xml, configname);
+ string rules;
+ getConfigTemplateXML(m_serverMode ? "server" : "client",
+ xml,
+ rules,
+ configname);
string tag;
size_t index;
BOOST_FOREACH(SyncSource *source, *m_sourceListPtr) {
string fragment;
source->getDatastoreXML(fragment, fragments);
- hash = Hash(source->getName()) % INT_MAX;
-
- /**
- * @TODO handle hash collisions
- */
- if (!hash) {
- hash = 1;
+ string name;
+
+ // Make sure that sub-datastores do not interfere with the global URI namespace
+ // by adding a <superdatastore>/ prefix. That way we can have a "calendar"
+ // alias for "calendar+todo" without conflicting with the underlying
+ // "calendar", which will be called "calendar+todo/calendar" in the XML config.
+ name = source->getVirtualSource();
+ if (!name.empty()) {
+ name += m_findSourceSeparator;
}
- datastores << " <datastore name='" << source->getName() << "' type='plugin'>\n" <<
- " <dbtypeid>" << hash << "</dbtypeid>\n" <<
+ name += source->getName();
+
+ datastores << " <datastore name='" << name << "' type='plugin'>\n" <<
+ " <dbtypeid>" << source->getSynthesisID() << "</dbtypeid>\n" <<
fragment;
string mode = source->getSync();
- const struct SourceList::SourceConfigSpecials &special =
- m_sourceListPtr->m_configSpecials[source->getName()];
- if (special.m_forceSlow) {
+ if (source->getForceSlowSync()) {
// we *want* a slow sync, but couldn't tell the client -> force it server-side
datastores << " <alertscript> FORCESLOWSYNC(); </alertscript>\n";
} else if (mode != "slow" &&
// so a slow sync is acceptable in this case
!m_serverMode &&
getPreventSlowSync() &&
- source->m_backupBefore.getNumItems() != 0) { // check is only relevant if we have local data;
- // if no backup was made (-1), better check
+ (!source->getOperations().m_isEmpty || // check is only relevant if we have local data;
+ !source->getOperations().m_isEmpty())) { // if we cannot check, assume we have data
// We are not expecting a slow sync => refuse to execute one.
// This is the client check for this, server must be handled
// differently (TODO, MB #2416).
datastores <<
- " <alertscript><![CDATA[\n"
- "INTEGER alertcode;\n"
- "alertcode = ALERTCODE();\n"
- "if (alertcode == 201) {\n" // SLOWSYNC() cannot be used here, refresh-from-client also sets it
- " DEBUGMESSAGE(\"slow sync not expected by SyncEvolution, disabling datastore\");\n"
- " ABORTDATASTORE(" << STATUS_UNEXPECTED_SLOW_SYNC <<
- ");\n"
- " // tell UI to abort instead of sending the next message\n"
- " SETSESSIONVAR(\"delayedabort\", 1);\n"
- "}\n"
- "]]></alertscript>\n";
+ " <datastoreinitscript><![CDATA[\n"
+ " if (SLOWSYNC() && ALERTCODE() != 203) {\n" // SLOWSYNC() is true for acceptable refresh-from-client, check for that
+ " DEBUGMESSAGE(\"slow sync not expected by SyncEvolution, disabling datastore\");\n"
+ " ABORTDATASTORE(" << sysync::LOCERR_DATASTORE_ABORT << ");\n"
+ " // tell UI to abort instead of sending the next message\n"
+ " SETSESSIONVAR(\"delayedabort\", 1);\n"
+ " }\n"
+ " ]]></datastoreinitscript>\n";
}
- if (m_serverMode && !special.m_alias.empty()) {
- datastores << " <alias name='" << special.m_alias << "'/>";
+ if (m_serverMode) {
+ string uri = source->getURI();
+ if (!uri.empty()) {
+ datastores << " <alias name='" << uri << "'/>";
+ }
}
datastores << " </datastore>\n\n";
/*If there is super datastore, add it here*/
//TODO generate specific superdatastore contents (MB #8753)
//Now only works for synthesis built-in events+tasks
- BOOST_FOREACH (boost::shared_ptr<VirtualSyncSource> vSource, m_sourceListPtr->m_virtualDS) {
+ BOOST_FOREACH (boost::shared_ptr<VirtualSyncSource> vSource, m_sourceListPtr->getVirtualSources()) {
std::string superType = vSource->getSourceType().m_format;
std::string evoSyncSource = vSource->getDatabaseID();
std::vector<std::string> mappedSources = unescapeJoinedString (evoSyncSource, ',');
- //only check the type when user uses forceFormat
- if (vSource->getSourceType().m_forceFormat) {
- if (superType.find_last_of (":") != superType.npos) {
- superType = superType.substr (superType.find_last_of (":"));
- }
- BOOST_FOREACH (std::string source, mappedSources) {
- //check the data type
- SyncSource *subSource = (*m_sourceListPtr)[source];
- std::string subType = subSource->getPeerMimeType();
- if (subType.empty()) {
- subType = subSource->getSourceType().m_format;
- if (subType.find_last_of (":") != subType.npos) {
- subType = subType.substr (subType.find_last_of (":"));
- }
- }
- if (superType != subType) {
- SE_LOG_WARNING (NULL, NULL,
- "Virtual datasource %s and sub datasource %s has different data format, will use the format in virtual datasource",
- vSource->getName(), source.c_str());
- break;
- }
- }
+ // always check for a consistent config
+ SourceType sourceType = vSource->getSourceType();
+ BOOST_FOREACH (std::string source, mappedSources) {
+ //check the data type
+ SyncSource *subSource = (*m_sourceListPtr)[source];
+ SourceType subType = subSource->getSourceType();
+ if (sourceType.m_format != subType.m_format ||
+ sourceType.m_forceFormat != subType.m_forceFormat) {
+ SE_LOG_WARNING(NULL, NULL,
+ "Virtual data source \"%s\" and sub data source \"%s\" have different data format. Will use the format in virtual data source.",
+ vSource->getName(), source.c_str());
+ }
}
if (mappedSources.size() !=2) {
- vSource->throwError ("virtual data source now only supports events+tasks case");
+ vSource->throwError ("virtual data source currently only supports events+tasks combinations");
}
- datastores << " <superdatastore name= '" << vSource->getName() <<"'> \n";
- datastores << " <contains datastore = '" << mappedSources[0] <<"'>\n"
+ string name = vSource->getName();
+ datastores << " <superdatastore name= '" << name << "'> \n";
+ datastores << " <contains datastore = '" << name << m_findSourceSeparator << mappedSources[0] <<"'>\n"
<< " <dispatchfilter>F.ISEVENT:=1</dispatchfilter>\n"
<< " <guidprefix>e</guidprefix>\n"
<< " </contains>\n"
- <<"\n <contains datastore = '" << mappedSources[1] <<"'>\n"
+ << "\n <contains datastore = '" << name << m_findSourceSeparator << mappedSources[1] <<"'>\n"
<< " <dispatchfilter>F.ISEVENT:=0</dispatchfilter>\n"
<< " <guidprefix>t</guidprefix>\n"
<<" </contains>\n" ;
+ if (m_serverMode) {
+ string uri = vSource->getURI();
+ if (!uri.empty()) {
+ datastores << " <alias name='" << uri << "'/>";
+ }
+ }
+
std::string typesupport;
typesupport = vSource->getDataTypeSupport();
- if (typesupport.empty()) {
- SE_THROW ("datatype format is not set in virtual datasource configuration");
- }
datastores << " <typesupport>\n"
<< typesupport
<< " </typesupport>\n";
substTag(xml, "fieldlists", fragments.m_fieldlists.join(), true);
substTag(xml, "profiles", fragments.m_profiles.join(), true);
- substTag(xml, "datatypes", fragments.m_datatypes.join(), true);
+ substTag(xml, "datatypedefs", fragments.m_datatypes.join(), true);
substTag(xml, "remoterules",
- string("<remoterule name='EVOLUTION'><deviceid>none - this rule is activated via its name in MAKE/PARSETEXTWITHPROFILE() macro calls</deviceid></remoterule>\n") +
+ rules +
fragments.m_remoterules.join(),
true);
xml.c_str());
throw;
}
- if (logXML) {
+ if (logXML &&
+ getLogLevel() >= 5) {
SE_LOG_DEV(NULL, NULL, "Full XML configuration:\n%s", xml.c_str());
}
}
sourceList.startSession(getLogDir(),
getMaxLogDirs(),
getLogLevel(),
- report,
- "client");
-
+ report);
/* Must detect server or client session before creating the
* underlying SynthesisEngine
}
// open each source - failing now is still safe
+ // in clients; in servers we wait until the source
+ // is really needed
BOOST_FOREACH(SyncSource *source, sourceList) {
if (m_serverMode) {
source->enableServerMode();
+ } else {
+ source->open();
}
- source->open();
- }
- // give derived class also a chance to update the configs
- prepare(sourceList);
+ // request callback when starting to use source
+ source->addCallback(boost::bind(&SyncContext::startSourceAccess, this, source), &SyncSource::Operations::m_startAccess);
+ }
- // TODO: in server mode don't dump all databases. Wait until
- // the client is logged in successfully and we know which
- // sources it needs.
- // ready to go: dump initial databases and prepare for final report
- sourceList.syncPrepare();
+ // ready to go
status = doSync();
} catch (...) {
// handle the exception here while the engine (and logging!) is still alive
/* For each virtual datasoruce, generate the SAN accoring to it and ignoring
* sub datasource in the later phase*/
- BOOST_FOREACH (boost::shared_ptr<VirtualSyncSource> vSource, m_sourceListPtr->m_virtualDS) {
+ BOOST_FOREACH (boost::shared_ptr<VirtualSyncSource> vSource, m_sourceListPtr->getVirtualSources()) {
std::string evoSyncSource = vSource->getDatabaseID();
std::string sync = vSource->getSync();
int mode = StringToSyncMode (sync, true);
BOOST_FOREACH (std::string source, mappedSources) {
dataSources.erase (source);
if (mode == SYNC_SLOW) {
- m_sourceListPtr->m_configSpecials[source].m_forceSlow = true;
+ // We force a source which the client is not expected to use into slow mode.
+ // Shouldn't we rather reject attempts to synchronize it?
+ (*m_sourceListPtr)[source]->setForceSlowSync(true);
}
}
dataSources.insert (vSource->getName());
string sync = sc->getSync();
int mode = StringToSyncMode (sync, true);
if (mode == SYNC_SLOW) {
- m_sourceListPtr->m_configSpecials[name].m_forceSlow = true;
+ (*m_sourceListPtr)[name]->setForceSlowSync(true);
mode = SA_SYNC_TWO_WAY;
}
if (mode <SYNC_FIRST || mode >SYNC_LAST) {
return true;
}
}
- } catch (TransportException e) {
- SE_LOG_ERROR (NULL, NULL, "TransportException while sending SAN package");
+ } catch (...) {
+ throw;
}
return false;
}
profile = m_engine.OpenSubkey(profiles, sysync::KEYVAL_ID_NEW_DEFAULT);
}
- m_engine.SetStrValue(profile, "serverURI", getSyncURL());
+ m_engine.SetStrValue(profile, "serverURI", getUsedSyncURL());
m_engine.SetStrValue(profile, "serverUser", getUsername());
m_engine.SetStrValue(profile, "serverPassword", getPassword());
m_engine.SetInt32Value(profile, "encoding",
target;
target = m_engine.OpenSubkey(targets, sysync::KEYVAL_ID_NEXT, true)) {
s = m_engine.GetStrValue(target, "dbname");
- SyncSource *source = (*m_sourceListPtr)[s];
+ SyncSource *source = findSource(s.c_str());
if (source) {
m_engine.SetInt32Value(target, "enabled", 1);
int slow = 0;
// Catch outgoing message and abort if requested by script.
// Report which sources are affected, based on their status code.
- list<string> sources;
+ set<string> sources;
BOOST_FOREACH(SyncSource *source, *m_sourceListPtr) {
if (source->getStatus() == STATUS_UNEXPECTED_SLOW_SYNC) {
- sources.push_back(source->getName());
+ string name = source->getVirtualSource();
+ if (name.empty()) {
+ name = source->getName();
+ }
+ sources.insert(name);
}
}
string explanation = SyncReport::slowSyncExplanation(m_server,
if (!m_serverMode) {
// specific for a certain sync source:
// find it...
- target = m_engine.OpenSubkey(targets, progressInfo.targetID);
- s = m_engine.GetStrValue(target, "dbname");
- SyncSource *source = (*m_sourceListPtr)[s];
+ SyncSource *source = m_sourceListPtr->lookupBySynthesisID(progressInfo.targetID);
if (source) {
displaySourceProgress(sysync::TProgressEventEnum(progressInfo.eventtype),
*source,
SE_LOG_INFO(NULL, NULL, "Local item changes:\n%s",
out.str().c_str());
- sourceList.startSession(getLogDir(), 0, 0, NULL, "status");
+ sourceList.startSession(getLogDir(), 0, 0, NULL);
LoggerBase::instance().setLevel(Logger::INFO);
string prevLogdir = sourceList.getPrevLogdir();
bool found = access(prevLogdir.c_str(), R_OK|X_OK) == 0;
try {
sourceList.setPath(prevLogdir);
sourceList.dumpDatabases("current", NULL);
- sourceList.dumpLocalChanges(sourceList.getPrevLogdir(), "after", "current");
+ sourceList.dumpLocalChanges("", "after", "current", "");
} catch(...) {
Exception::handle();
}
if (!report.empty()) {
stringstream out;
report.prettyPrint(out, SyncReport::WITHOUT_SERVER|SyncReport::WITHOUT_CONFLICTS|SyncReport::WITH_TOTAL);
- SE_LOG_INFO(NULL, NULL, "Item changes %s applied to client during restore:\n%s",
+ SE_LOG_INFO(NULL, NULL, "Item changes %s applied locally during restore:\n%s",
dryrun ? "to be" : "that were",
out.str().c_str());
SE_LOG_INFO(NULL, NULL, "The same incremental changes will be applied to the server during the next sync.");
}
SourceList sourceList(*this, false);
- sourceList.startSession(dirname.c_str(), 0, 0, NULL, "restore");
+ sourceList.startSession(dirname.c_str(), 0, 0, NULL);
LoggerBase::instance().setLevel(Logger::INFO);
initSources(sourceList);
BOOST_FOREACH(SyncSource *source, sourceList) {
if (!m_quiet) {
sourceList.dumpDatabases("current", NULL);
- sourceList.dumpLocalChanges(dirname, "current", datadump,
- "Data changes to be applied to local data during restore:\n",
+ sourceList.dumpLocalChanges(dirname, "current", datadump, "",
+ "Data changes to be applied locally during restore:\n",
"CLIENT_TEST_LEFT_NAME='current data' "
"CLIENT_TEST_REMOVED='after restore' "
"CLIENT_TEST_REMOVED='to be removed' "
void SyncContext::getSessions(vector<string> &dirs)
{
LogDir logging(*this);
- logging.previousLogdirs(getLogDir(), dirs);
+ logging.previousLogdirs(dirs);
}
string SyncContext::readSessionInfo(const string &dir, SyncReport &report)
return logging.getPeerNameFromLogdir(dir);
}
+#ifdef ENABLE_UNIT_TESTS
+/**
+ * This class works LogDirTest as scratch directory.
+ * LogDirTest/[ical20|vcard30]_[one|two|empty] contain different
+ * sets of items for use in a FileSyncSource.
+ *
+ * With that setup and a fake SyncContext it is possible to simulate
+ * sessions and test the resulting logdirs.
+ */
+class LogDirTest : public CppUnit::TestFixture, private SyncContext
+{
+public:
+ LogDirTest() :
+ SyncContext("nosuchconfig@nosuchcontext"),
+ m_maxLogDirs(10)
+ {}
+
+ void setUp() {
+ static const char *vcard_1 =
+ "BEGIN:VCARD\n"
+ "VERSION:2.1\n"
+ "TITLE:tester\n"
+ "FN:John Doe\n"
+ "N:Doe;John;;;\n"
+ "X-MOZILLA-HTML:FALSE\n"
+ "TEL;TYPE=WORK;TYPE=VOICE:business 1\n"
+ "EMAIL:john.doe@work.com\n"
+ "X-AIM:AIM JOHN\n"
+ "END:VCARD\n";
+ static const char *vcard_2 =
+ "BEGIN:VCARD\n"
+ "VERSION:2.1\n"
+ "TITLE:developer\n"
+ "FN:John Doe\n"
+ "N:Doe;John;;;\n"
+ "X-MOZILLA-HTML:TRUE\n"
+ "BDAY:2006-01-08\n"
+ "END:VCARD\n";
+ static const char *ical_1 =
+ "BEGIN:VCALENDAR\n"
+ "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
+ "VERSION:2.0\n"
+ "METHOD:PUBLISH\n"
+ "BEGIN:VEVENT\n"
+ "SUMMARY:phone meeting\n"
+ "DTEND:20060406T163000Z\n"
+ "DTSTART:20060406T160000Z\n"
+ "UID:1234567890!@#$%^&*()<>@dummy\n"
+ "DTSTAMP:20060406T211449Z\n"
+ "LAST-MODIFIED:20060409T213201\n"
+ "CREATED:20060409T213201\n"
+ "LOCATION:calling from home\n"
+ "DESCRIPTION:let's talk\n"
+ "CLASS:PUBLIC\n"
+ "TRANSP:OPAQUE\n"
+ "SEQUENCE:1\n"
+ "BEGIN:VALARM\n"
+ "DESCRIPTION:alarm\n"
+ "ACTION:DISPLAY\n"
+ "TRIGGER;VALUE=DURATION;RELATED=START:-PT15M\n"
+ "END:VALARM\n"
+ "END:VEVENT\n"
+ "END:VCALENDAR\n";
+ static const char *ical_2 =
+ "BEGIN:VCALENDAR\n"
+ "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
+ "VERSION:2.0\n"
+ "METHOD:PUBLISH\n"
+ "BEGIN:VEVENT\n"
+ "SUMMARY:phone meeting\n"
+ "DTEND:20060406T163000Z\n"
+ "DTSTART:20060406T160000Z\n"
+ "UID:1234567890!@#$%^&*()<>@dummy\n"
+ "DTSTAMP:20060406T211449Z\n"
+ "LAST-MODIFIED:20060409T213201\n"
+ "CREATED:20060409T213201\n"
+ "LOCATION:my office\n"
+ "CATEGORIES:WORK\n"
+ "DESCRIPTION:what the heck\\, let's even shout a bit\n"
+ "CLASS:PUBLIC\n"
+ "TRANSP:OPAQUE\n"
+ "SEQUENCE:1\n"
+ "END:VEVENT\n"
+ "END:VCALENDAR\n";
+ rm_r("LogDirTest");
+ dump("ical20.one", "1", ical_1);
+ dump("ical20.two", "1", ical_1);
+ dump("ical20.two", "2", ical_2);
+ mkdir_p(getLogData() + "/ical20.empty");
+ dump("vcard30.one", "1", vcard_1);
+ dump("vcard30.two", "1", vcard_1);
+ dump("vcard30.two", "2", vcard_2);
+ mkdir_p(getLogData() + "/vcard30.empty");
+
+ mkdir_p(getLogDir());
+ m_maxLogDirs = 0;
+ }
+
+private:
+
+ string getLogData() { return "LogDirTest/data"; }
+ virtual const char *getLogDir() { return "LogDirTest/cache/syncevolution"; }
+ int m_maxLogDirs;
+
+ void dump(const char *dir, const char *file, const char *data) {
+ string name = getLogData();
+ name += "/";
+ name += dir;
+ mkdir_p(name);
+ name += "/";
+ name += file;
+ ofstream out(name.c_str());
+ out << data;
+ }
+
+ CPPUNIT_TEST_SUITE(LogDirTest);
+ CPPUNIT_TEST(testQuickCompare);
+ CPPUNIT_TEST(testSessionNoChanges);
+ CPPUNIT_TEST(testSessionChanges);
+ CPPUNIT_TEST(testMultipleSessions);
+ CPPUNIT_TEST(testExpire);
+ CPPUNIT_TEST(testExpire2);
+ CPPUNIT_TEST_SUITE_END();
+
+ /**
+ * Simulate a session involving one or more sources.
+ *
+ * @param changeServer pretend that peer got changed
+ * @param status result of session
+ * @param varargs sourcename ("ical20"),
+ * statebefore (NULL for no dump, or suffix like "_one"),
+ * stateafter (NULL for same as before), ..., NULL
+ * @return logdir created for the session
+ */
+ string session(bool changeServer, SyncMLStatus status, ...) {
+ SourceList list(*this, true);
+ list.setLogLevel(SourceList::LOGGING_QUIET);
+ SyncReport report;
+ list.startSession(NULL, m_maxLogDirs, 0, &report);
+ va_list ap;
+ va_start(ap, status);
+ while (true) {
+ const char *sourcename = va_arg(ap, const char *);
+ if (!sourcename) {
+ break;
+ }
+ const char *type = NULL;
+ if (!strcmp(sourcename, "ical20")) {
+ type = "file:text/calendar:2.0";
+ } else if (!strcmp(sourcename, "vcard30")) {
+ type = "file:text/vcard:3.0";
+ }
+ CPPUNIT_ASSERT(type);
+ string datadir = getLogData() + "/";
+ cxxptr<SyncSource> source(SyncSource::createTestingSource(sourcename, type, true,
+ (string("file://") + datadir).c_str()));
+ datadir += sourcename;
+ datadir += "_1";
+ source->open();
+ if (changeServer) {
+ // fake one added item on server
+ source->setItemStat(SyncSourceReport::ITEM_REMOTE,
+ SyncSourceReport::ITEM_ADDED,
+ SyncSourceReport::ITEM_TOTAL,
+ 1);
+ }
+ list.addSource(source);
+ const char *before = va_arg(ap, const char *);
+ const char *after = va_arg(ap, const char *);
+ if (before) {
+ // do a "before" dump after directing the source towards the desired data
+ rm_r(datadir);
+ CPPUNIT_ASSERT_EQUAL(0, symlink((string(sourcename) + before).c_str(),
+ datadir.c_str()));
+ list.syncPrepare(sourcename);
+ if (after) {
+ rm_r(datadir);
+ CPPUNIT_ASSERT_EQUAL(0, symlink((string(sourcename) + after).c_str(),
+ datadir.c_str()));
+ }
+ }
+ }
+ list.syncDone(status, &report);
+
+ return list.getLogdir();
+ }
+
+ typedef vector<string> Sessions_t;
+ // full paths to all sessions, sorted
+ Sessions_t listSessions() {
+ Sessions_t sessions;
+ string logdir = getLogDir();
+ ReadDir dirs(logdir);
+ BOOST_FOREACH(const string &dir, dirs) {
+ sessions.push_back(logdir + "/" + dir);
+ }
+ sort(sessions.begin(), sessions.end());
+ return sessions;
+ }
+
+ void testQuickCompare() {
+ // identical dirs => identical files
+ CPPUNIT_ASSERT(!LogDir::haveDifferentContent("ical20",
+ getLogData(), "empty",
+ getLogData(), "empty"));
+ CPPUNIT_ASSERT(!LogDir::haveDifferentContent("ical20",
+ getLogData(), "one",
+ getLogData(), "one"));
+ CPPUNIT_ASSERT(!LogDir::haveDifferentContent("ical20",
+ getLogData(), "two",
+ getLogData(), "two"));
+ // some files shared
+ CPPUNIT_ASSERT(!system("cp -l -r LogDirTest/data/ical20.two LogDirTest/data/ical20.copy && rm LogDirTest/data/ical20.copy/2"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("ical20",
+ getLogData(), "two",
+ getLogData(), "copy"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("ical20",
+ getLogData(), "copy",
+ getLogData(), "one"));
+ }
+
+ void testSessionNoChanges() {
+ ScopedEnvChange config("XDG_CONFIG_HOME", "LogDirTest/config");
+ ScopedEnvChange cache("XDG_CACHE_HOME", "LogDirTest/cache");
+
+ // simple session with no changes
+ string dir = session(false, STATUS_OK, "ical20", ".one", ".one", (char *)0);
+ Sessions_t sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dir, sessions[0]);
+ FileConfigNode status(dir, "status.ini", true);
+ CPPUNIT_ASSERT(status.exists());
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-ical20-backup-before"));
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-ical20-backup-after"));
+ CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status"));
+ CPPUNIT_ASSERT(!LogDir::haveDifferentContent("ical20",
+ dir, "before",
+ dir, "after"));
+ }
+
+ void testSessionChanges() {
+ ScopedEnvChange config("XDG_CONFIG_HOME", "LogDirTest/config");
+ ScopedEnvChange cache("XDG_CACHE_HOME", "LogDirTest/cache");
+
+ // session with local changes
+ string dir = session(false, STATUS_OK, "ical20", ".one", ".two", (char *)0);
+ Sessions_t sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dir, sessions[0]);
+ FileConfigNode status(dir, "status.ini", true);
+ CPPUNIT_ASSERT(status.exists());
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-ical20-backup-before"));
+ CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-ical20-backup-after"));
+ CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("ical20",
+ dir, "before",
+ dir, "after"));
+ }
+
+ void testMultipleSessions() {
+ ScopedEnvChange config("XDG_CONFIG_HOME", "LogDirTest/config");
+ ScopedEnvChange cache("XDG_CACHE_HOME", "LogDirTest/cache");
+
+ // two sessions, starting with 1 item, adding 1 during the sync, then
+ // removing it again during the second
+ string dir = session(false, STATUS_OK,
+ "ical20", ".one", ".two",
+ "vcard30", ".one", ".two",
+ (char *)0);
+ {
+ Sessions_t sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dir, sessions[0]);
+ FileConfigNode status(dir, "status.ini", true);
+ CPPUNIT_ASSERT(status.exists());
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-ical20-backup-before"));
+ CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-ical20-backup-after"));
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-vcard30-backup-before"));
+ CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-vcard30-backup-after"));
+ CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("ical20",
+ dir, "before",
+ dir, "after"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("vcard30",
+ dir, "before",
+ dir, "after"));
+ }
+
+ string seconddir = session(false, STATUS_OK,
+ "ical20", ".two", ".one",
+ "vcard30", ".two", ".one",
+ (char *)0);
+ {
+ Sessions_t sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dir, sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(seconddir, sessions[1]);
+ FileConfigNode status(seconddir, "status.ini", true);
+ CPPUNIT_ASSERT(status.exists());
+ CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-ical20-backup-before"));
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-ical20-backup-after"));
+ CPPUNIT_ASSERT_EQUAL(string("2"), status.readProperty("source-vcard30-backup-before"));
+ CPPUNIT_ASSERT_EQUAL(string("1"), status.readProperty("source-vcard30-backup-after"));
+ CPPUNIT_ASSERT_EQUAL(string("200"), status.readProperty("status"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("ical20",
+ seconddir, "before",
+ seconddir, "after"));
+ CPPUNIT_ASSERT(LogDir::haveDifferentContent("vcard30",
+ seconddir, "before",
+ seconddir, "after"));
+ }
+
+ CPPUNIT_ASSERT(!LogDir::haveDifferentContent("ical20",
+ dir, "after",
+ seconddir, "before"));
+ CPPUNIT_ASSERT(!LogDir::haveDifferentContent("vcard30",
+ dir, "after",
+ seconddir, "before"));
+ }
+
+ void testExpire() {
+ ScopedEnvChange config("XDG_CONFIG_HOME", "LogDirTest/config");
+ ScopedEnvChange cache("XDG_CACHE_HOME", "LogDirTest/cache");
+
+ string dirs[5];
+ Sessions_t sessions;
+
+ m_maxLogDirs = 1;
+
+ // The latest session always must be preserved, even if it
+ // is normally considered less important (no error in this case).
+ dirs[0] = session(false, STATUS_FATAL, (char *)0);
+ dirs[0] = session(false, STATUS_OK, (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+
+ // all things being equal, then expire the oldest session,
+ // leaving us with two here
+ m_maxLogDirs = 2;
+ dirs[0] = session(false, STATUS_OK, (char *)0);
+ dirs[1] = session(false, STATUS_OK, (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(dirs[1], sessions[1]);
+
+ // When syncing first ical20, then vcard30, both sessions
+ // must be preserved despite m_maxLogDirs = 1, otherwise
+ // we would loose the only existent backup of ical20.
+ dirs[0] = session(false, STATUS_OK, "ical20", ".two", ".one", (char *)0);
+ dirs[1] = session(false, STATUS_OK, "vcard30", ".two", ".one", (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(dirs[1], sessions[1]);
+
+ // after synchronizing both, we can expire both the old sessions
+ m_maxLogDirs = 1;
+ dirs[0] = session(false, STATUS_OK,
+ "ical20", ".two", ".one",
+ "vcard30", ".two", ".one",
+ (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)1, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ }
+
+ void testExpire2() {
+ ScopedEnvChange config("XDG_CONFIG_HOME", "LogDirTest/config");
+ ScopedEnvChange cache("XDG_CACHE_HOME", "LogDirTest/cache");
+ string dirs[5];
+ Sessions_t sessions;
+
+ // Have to restart with clean log dir because our sequence counter
+ // runs over after 10 sessions. Continue where testExpire() stopped.
+ dirs[0] = session(false, STATUS_OK,
+ "ical20", ".two", ".one",
+ "vcard30", ".two", ".one",
+ (char *)0);
+
+ // when doing multiple failed syncs without dumps, keep the sessions
+ // which have database dumps
+ m_maxLogDirs = 2;
+ dirs[1] = session(false, STATUS_FATAL, (char *)0);
+ dirs[1] = session(false, STATUS_FATAL, (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(dirs[1], sessions[1]);
+
+ // when doing syncs which don't change data, keep the sessions which
+ // did change something: keep oldest backup because it created the
+ // backups for the first time
+ dirs[1] = session(false, STATUS_OK,
+ "ical20", ".one", ".one",
+ "vcard30", ".one", ".one",
+ (char *)0);
+ dirs[1] = session(false, STATUS_OK,
+ "ical20", ".one", ".one",
+ "vcard30", ".one", ".one",
+ (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(dirs[1], sessions[1]);
+
+ // when making a change in each sync, we end up with the two
+ // most recent sessions eventually: first change server,
+ // then local
+ dirs[1] = session(true, STATUS_OK,
+ "ical20", ".one", ".one",
+ "vcard30", ".one", ".one",
+ (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(dirs[1], sessions[1]);
+ dirs[0] = dirs[1];
+ dirs[1] = session(false, STATUS_OK,
+ "ical20", ".one", ".two",
+ "vcard30", ".one", ".two",
+ (char *)0);
+ sessions = listSessions();
+ CPPUNIT_ASSERT_EQUAL((size_t)2, sessions.size());
+ CPPUNIT_ASSERT_EQUAL(dirs[0], sessions[0]);
+ CPPUNIT_ASSERT_EQUAL(dirs[1], sessions[1]);
+ }
+};
+SYNCEVOLUTION_TEST_SUITE_REGISTRATION(LogDirTest);
+#endif // ENABLE_UNIT_TESTS
+
SE_END_CXX
}
};
+ /*
+ * The URL this SyncContext is actually using, since we may support multiple
+ * urls in the configuration.
+ * */
+ string m_usedSyncURL;
public:
/**
* SyncContext using a volatile config
* session. Called by Synthesis DB plugin to find active
* sources.
*
+ * @param name can be both <SyncSource::getName()> as well as <prefix>_<SyncSource::getName()>
+ * (necessary when renaming sources in the Synthesis XML config)
+ *
* @TODO: roll SourceList into SyncContext and
* make this non-static
*/
static SyncSource *findSource(const char *name);
+ static const char m_findSourceSeparator = '@';
/**
* Find the active sync context for the given session.
/**
* Return skeleton Synthesis client XML configuration.
*
- * If it contains a <datastore/> element, then that element will
- * be replaced by the configurations of all active sync
- * sources. Otherwise the configuration is used as-is.
+ * The <scripting/>, <datatypes/>, <clientorserver/> elements (if
+ * present) are replaced by the caller with fragments found in the
+ * file system. When <datatypes> already has content, that content
+ * may contain <fieldlists/>, <profiles/>, <datatypedefs/>, which
+ * will be replaced by definitions gathered from backends.
*
* The default implementation of this function takes the configuration from
* (in this order):
- * - ./syncevolution.xml
- * - <server config dir>/syncevolution.xml
- * - built-in default
+ * - $(XDG_CONFIG_HOME)/syncevolution-xml
+ * - $(datadir)/syncevolution/xml
+ * Files with identical names are read from the first location where they
+ * are found. If $(SYNCEVOLUTION_XML_CONFIG_DIR) is set, then it overrides
+ * the previous two locations.
+ *
+ * The syncevolution.xml file is read from the first place where it is found.
+ * In addition, further .xml files in sub-directories are gathered and get
+ * inserted into the syncevolution.xml template.
*
+ * If none of these locations has XML configs, then builtin strings are
+ * used as fallback. This only works for mode == "client". Otherwise an
+ * error is thrown.
+ *
+ * @param mode "client" or "server"
* @retval xml is filled with Synthesis client config which may hav <datastore/>
+ * @retval rules remote rules which the caller needs for <clientorserver/>
* @retval configname a string describing where the config came from
*/
- virtual void getConfigTemplateXML(string &xml, string &configname);
+ virtual void getConfigTemplateXML(const string &mode,
+ string &xml,
+ string &rules,
+ string &configname);
+
/**
* Return complete Synthesis XML configuration.
virtual void prepare() {}
/**
- * Callback for derived classes: called after setting up the client's
- * and sources' configuration. Can be used to reconfigure sources before
- * actually starting the synchronization.
- *
- * @param sources a NULL terminated array of all active sources
- */
- virtual void prepare(const std::vector<SyncSource *> &sources) {}
-
- /**
* instantiate transport agent
*
* Called by engine when it needs to do HTTP POST requests. The
* The default implementation instantiates one of the builtin
* transport agents, depending on how it was compiled.
*
+ * @param gmainloop the GMainLoop to be used by transports, if not NULL;
+ * transports not supporting that should not be created;
+ * transports will increase the reference count for the loop
* @return transport agent
*/
- virtual boost::shared_ptr<TransportAgent> createTransportAgent();
+ virtual boost::shared_ptr<TransportAgent> createTransportAgent(void *gmainloop);
+ virtual boost::shared_ptr<TransportAgent> createTransportAgent() { return createTransportAgent(NULL); }
/**
* display a text message from the server
void initSources(SourceList &sourceList);
/**
+ * called by SynthesDBPlugin in SyncEvolution_StartDataRead()
+ */
+ void startSourceAccess(SyncSource *source);
+
+ /**
* utility function for status() and getChanges():
* iterate over sources, check for changes and copy result
*/
public:
static bool transport_cb (void *data);
void setTransportCallback(int seconds);
+
+ string getUsedSyncURL();
};
SE_END_CXX
+++ /dev/null
-const char *SyncEvolutionXML =
-"<?xml version=\"1.0\"?>\n"
-"<!-- SYNTHESIS SYNCML CLIENT Version 3.2 Configuration file -->\n"
-"\n"
-"<sysync_config version=\"1.0\">\n"
-"\n"
-" <configvar name=\"logpath\" value=\"$(defout_path)\"/>\n"
-"\n"
-" <!-- this string is output to every session debug logfile to identify the config in use -->\n"
-" <configidstring>SyncEvolution client config</configidstring>\n"
-"\n"
-" <!-- information about maximum supported message and object size (in bytes) -->\n"
-" <maxmsgsize/>\n"
-" <maxobjsize/>\n"
-"\n"
-" <!-- information for DevInf -->\n"
-" <model/>\n"
-" <manufacturer/>\n"
-" <hardwareversion/>\n"
-" <firmwareversion/>\n"
-" <devicetype/>\n"
-" <configdate/>\n"
-"\n"
-" <debug/>\n"
-"\n"
-" <transport type=\"xpt\">\n"
-" <!-- allow HTTP 1.1 kepp-alive (multiple request-answer-exchanges in single TCP connection) -->\n"
-" <keepconnection>true</keepconnection>\n"
-" </transport>\n"
-"\n"
-"\n"
-" <scripting>\n"
-" <looptimeout>5</looptimeout>\n"
-"\n"
-" <function><![CDATA[\n"
-" // create a UID\n"
-" string newuid() {\n"
-" return \"syuid\" + NUMFORMAT(RANDOM(1000000),6,\"0\") + \".\" + (string)MILLISECONDS(NOW());\n"
-" }\n"
-" ]]></function>\n"
-" <macro name=\"VCARD_BEFOREWRITE_SCRIPT_EVOLUTION\"><![CDATA[\n"
-" // a wordaround for cellphone in evolution. for incoming contacts, if there is only one CELL,\n"
-" // strip the HOME or WORK flag from it. Evolution then should show it. */\n"
-" INTEGER i, wanted, cell_phones;\n"
-" i = 0;\n"
-" cell_phones = 0;\n"
-" while(i < SIZE(TEL_FLAGS)) {\n"
-" // 0x10 is the flag of 'cell' type of telephone\n"
-" if(TEL_FLAGS[i] & 0x10) {\n"
-" cell_phones = cell_phones + 1;\n"
-" wanted = i;\n"
-" }\n"
-" i = i + 1;\n"
-" }\n"
-" if(cell_phones == 1) {\n"
-" TEL_FLAGS[wanted] = 0x10;\n"
-" }\n"
-"\n"
-" // Google sends TYPE=WORK and TYPE=HOME when it means\n"
-" // normal VOICE phone numbers. Add that flag when\n"
-" // importing into Evolution, because Evolution does not\n"
-" // display the numbers without VOICE.\n"
-" i = 0;\n"
-" while(i < SIZE(TEL_FLAGS)) {\n"
-" if(TEL_FLAGS[i] == 1 || TEL_FLAGS[i] == 2) {\n"
-" TEL_FLAGS[i] = TEL_FLAGS[i] | 8;\n"
-" }\n"
-" i = i + 1;\n"
-" }\n"
-" ]]></macro>\n"
-" <macro name=\"VCALENDAR_20TO10_PRIORITY_CONVERSION\"><![CDATA[\n"
-" //vCalendar10 has different interpretation from iCalendar20 in 'priority'.\n"
-" //see mappings: \n"
-" // Category vCalendar1.0 iCalendar2.0\n"
-" // undefined 0 0\n"
-" // high 1 1 ~ 4\n"
-" // normal 2 5\n"
-" // low 3 6 ~ bigger\n"
-" if(PRIORITY<5 && PRIORITY>0) {\n"
-" PRIORITY=1;\n"
-" }else if(PRIORITY==5){\n"
-" PRIORITY=2;\n"
-" }else if(PRIORITY>5){\n"
-" PRIORITY=3;\n"
-" } // 0 is undefined and remains unchanged\n"
-" ]]></macro>\n"
-" <macro name=\"VCALENDAR_10TO20_PRIORITY_CONVERSION\"><![CDATA[\n"
-" if(PRIORITY==2) {\n"
-" PRIORITY=5;\n"
-" }else if(PRIORITY==3){\n"
-" PRIORITY=7;\n"
-" } //others remain unchanged\n"
-" ]]></macro>\n"
-" <macro name=\"VCALENDAR10_BEFOREWRITE_SCRIPT\"><![CDATA[\n"
-" $VCALENDAR_20TO10_PRIORITY_CONVERSION;\n"
-" ]]></macro>\n"
-" <macro name=\"VCALENDAR10_AFTERREAD_SCRIPT\"><![CDATA[\n"
-" $VCALENDAR_10TO20_PRIORITY_CONVERSION;\n"
-" ]]></macro>\n"
-"\n"
-" <macro name=\"VCARD_INCOMING_NAMECHANGE_SCRIPT\"><![CDATA[\n"
-" STRING tmp;\n"
-" tmp=NORMALIZED(FN);\n"
-" if (tmp==EMPTY){\n"
-" tmp=N_FIRST;\n"
-" if (N_MIDDLE != EMPTY) {\n"
-" if (tmp != EMPTY) {\n"
-" tmp = tmp + \" \";\n"
-" }\n"
-" tmp = tmp + N_MIDDLE;\n"
-" }\n"
-" if (N_LAST != EMPTY) {\n"
-" if (tmp != EMPTY) {\n"
-" tmp = tmp + \" \";\n"
-" }\n"
-" tmp = tmp + N_LAST;\n"
-" }\n"
-" FN = tmp;\n"
-" }\n"
-" ]]></macro>\n"
-"\n"
-" <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->\n"
-"\n"
-" <macro name=\"VCALENDAR_INCOMING_SCRIPT\"><![CDATA[\n"
-" STRING MATCHES[];\n"
-" STRING CAT,CN,EM;\n"
-" INTEGER i;\n"
-" // make sure we have all trailing and leading spaces eliminated\n"
-" DESCRIPTION=NORMALIZED(DESCRIPTION);\n"
-" SUMMARY=NORMALIZED(SUMMARY);\n"
-" // make sure that we have a DESCRIPTION\n"
-" if (DESCRIPTION==EMPTY) DESCRIPTION=SUMMARY;\n"
-" // calendar or todo\n"
-" if (ISEVENT) {\n"
-" // VEVENT\n"
-" // - handle duration cases \n"
-" if (ISDURATION(DURATION)) {\n"
-" if (DTEND==EMPTY) DTEND = DTSTART + DURATION;\n"
-" if (DTSTART==EMPTY) DTSTART = DTEND - DURATION;\n"
-" }\n"
-" // - detect alldays in vCalendar 1.0 (0:00-0:00 or 23:59 localtime)\n"
-" i = ALLDAYCOUNT(DTSTART,DTEND,TRUE);\n"
-" if (ITEMDATATYPE()==\"vCalendar10\" && i>0) {\n"
-" // DTSTART and DTEND represent allday event, make them date-only values\n"
-" // - convert start to user zone (or floating) so it represents midnight\n"
-" DTSTART = CONVERTTOUSERZONE(DTSTART);\n"
-" MAKEALLDAY(DTSTART,DTEND,i);\n"
-" }\n"
-"\n"
-" // Make sure that all EXDATE times are in the same timezone as the start\n"
-" // time. Some servers send them as UTC, which is all fine and well, but\n"
-" // only if the timezone definition doesn't change. Also, libical does not\n"
-" // handle such UTC EXDATEs, so let's convert it while the UTC and\n"
-" // time zone definition (hopefully) are in sync.\n"
-" if (TIMEZONE(DTSTART) != \"UTC\" && !ISFLOATING(DTSTART)) {\n"
-" i = 0;\n"
-" timestamp exdate;\n"
-" while (i<SIZE(EXDATES)) {\n"
-" exdate = EXDATES[i];\n"
-" if (!ISDATEONLY(exdate) &&\n"
-" (TIMEZONE(exdate) == \"UTC\" || ISFLOATING(exdate))) {\n"
-" // \"unfloat\" floating time stamps: not sure whether that occcurs\n"
-" // in practice, but it looks as wrong as UTC EXDATEs\n"
-" EXDATES[i] = CONVERTTOZONE(exdate,DTSTART,TRUE);\n"
-" }\n"
-" i=i+1;\n"
-" }\n"
-" }\n"
-" // If vcalendar1.0, rrule is not secondly, minutely, or hourly, we strip time information\n"
-" // and only reserve date information\n"
-" if (ITEMDATATYPE()==\"vCalendar10\" && RR_FREQ!=\"h\" && RR_FREQ!=\"m\" && RR_FREQ!=\"s\") {\n"
-" timestamp exdate;\n"
-" i = 0;\n"
-" while (i<SIZE(EXDATES)) {\n"
-" exdate = EXDATES[i];\n"
-" if (!ISDATEONLY(exdate)) {\n"
-" EXDATES[i] = DATEONLY(exdate);\n"
-" }\n"
-" i=i+1;\n"
-" } \n"
-" }\n"
-"\n"
-" // - shape attendees (and make sure ATTENDEES[] is assigned even for empty email addresses)\n"
-" i=0;\n"
-" while(i<SIZE(ATTENDEES) || i<SIZE(ATTENDEE_CNS)) {\n"
-" PARSEEMAILSPEC(ATTENDEES[i], CN, EM);\n"
-" ATTENDEES[i] = EM; // pure email address\n"
-" // in case we have no specific common name, use the one extracted from the email\n"
-" // This catches the vCalendar 1.0 case and eventually ill-formed iCalendar 2.0 as well\n"
-" if (ATTENDEE_CNS[i]==EMPTY)\n"
-" ATTENDEE_CNS[i]=CN;\n"
-" // default participation status to needs-action\n"
-" if (ATTENDEE_PARTSTATS[i]==EMPTY)\n"
-" ATTENDEE_PARTSTATS[i]=1; // 1=needs action\n"
-" i=i+1;\n"
-" }\n"
-" // - shape organizer\n"
-" PARSEEMAILSPEC(ORGANIZER, CN, EM);\n"
-" ORGANIZER = EM; // pure email address\n"
-" if (ORGANIZER_CN==EMPTY)\n"
-" ORGANIZER_CN=CN;\n"
-" }\n"
-" else {\n"
-" // VTODO\n"
-" // - make sure we have at least a summary\n"
-" if (SUMMARY==EMPTY) SUMMARY=DESCRIPTION; // use description if we don't have a summary\n"
-" if (SUMMARY==EMPTY) SUMMARY=\"unnamed\"; // set dummy summary if we still don't have one\n"
-" // due shaping for non-iCalendar 2.0\n"
-" if (ITEMDATATYPE()==\"vCalendar10\" && ALLDAYCOUNT(DUE,DUE,TRUE,TRUE)>0) {\n"
-" DUE = DATEONLY(DUE);\n"
-" }\n"
-" if (ITEMDATATYPE()==\"vCalendar10\") {\n"
-" $VCALENDAR_10TO20_PRIORITY_CONVERSION;\n"
-" }\n"
-" }\n"
-" // a workaround for funambol: adding 'action' for 'alarm'\n"
-" if (ITEMDATATYPE()==\"iCalendar20\") {\n"
-" if (ALARM_TIME!=EMPTY && ALARM_ACTION==EMPTY) {\n"
-" ALARM_ACTION = \"DISPLAY\";\n"
-" }\n"
-" }\n"
-" ]]></macro>\n"
-"\n"
-" <macro name=\"VCALENDAR_OUTGOING_SCRIPT\"><![CDATA[\n"
-" // set UTC time of generation for iCalendar 2.0 DTSTAMP\n"
-" DGENERATED = NOW();\n"
-" // make sure we have all trailing and leading spaces eliminated\n"
-" DESCRIPTION=NORMALIZED(DESCRIPTION);\n"
-" SUMMARY=NORMALIZED(SUMMARY);\n"
-" if (ISEVENT) {\n"
-" // VEVENT\n"
-" // - combine attendee email address and common name into single string for vCalendar 1.0\n"
-" if (ITEMDATATYPE()==\"vCalendar10\") {\n"
-" i=0;\n"
-" while(i<SIZE(ATTENDEES)) {\n"
-" ATTENDEES[i] = MAKEEMAILSPEC(ATTENDEE_CNS[i], ATTENDEES[i]);\n"
-" i=i+1;\n"
-" }\n"
-" ORGANIZER = MAKEEMAILSPEC(ORGANIZER_CN, ORGANIZER);\n"
-" }\n"
-" }\n"
-" else {\n"
-" // VTODO \n"
-" // interal representation is iCalendar20\n"
-" if (ITEMDATATYPE()==\"vCalendar10\") {\n"
-" $VCALENDAR_20TO10_PRIORITY_CONVERSION;\n"
-" }\n"
-" }\n"
-" // make sure we have at least a summary\n"
-" if (SUMMARY==EMPTY) SUMMARY=SUBSTR(DESCRIPTION,0,32); // derive from description\n"
-" if (SUMMARY==EMPTY) SUMMARY=\"unnamed\"; // in case description is empty as well\n"
-" // make sure that we have a DESCRIPTION\n"
-" if (DESCRIPTION==EMPTY) DESCRIPTION=SUMMARY;\n"
-" // do NOT send duration (some servers crash when doing so)\n"
-" DURATION = UNASSIGNED;\n"
-" // shape alarm\n"
-" if (ALARM_TIME!=EMPTY) {\n"
-" if (ITEMDATATYPE()==\"iCalendar20\") {\n"
-" if (ALARM_ACTION==EMPTY) ALARM_ACTION = \"AUDIO\";\n"
-" }\n"
-" else {\n"
-" if (ALARM_MSG==EMPTY) ALARM_MSG=\"alarm\";\n"
-" }\n"
-" }\n"
-" ]]></macro>\n"
-"\n"
-" </scripting>\n"
-"\n"
-"\n"
-" <datatypes>\n"
-"\n"
-" <!-- list of internal fields representing vCard data -->\n"
-" <fieldlist name=\"contacts\">\n"
-" <field name=\"REV\" type=\"timestamp\" compare=\"never\" age=\"yes\"/>\n"
-"\n"
-" <!-- Name elements -->\n"
-" <field name=\"N_LAST\" type=\"string\" compare=\"always\"/>\n"
-" <field name=\"N_FIRST\" type=\"string\" compare=\"always\"/>\n"
-" <field name=\"N_MIDDLE\" type=\"string\" compare=\"always\"/>\n"
-" <field name=\"N_PREFIX\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"N_SUFFIX\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"NICKNAME\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"TITLE\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <field name=\"FN\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"FILE-AS\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <field name=\"GENDER\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <!-- categories and classification -->\n"
-" <field name=\"CATEGORIES\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- organisation -->\n"
-" <field name=\"ORG_NAME\" type=\"string\" compare=\"slowsync\" merge=\"fillempty\"/>\n"
-" <field name=\"ORG_DIVISION\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"ORG_OFFICE\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"ORG_TEAM\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"ROLE\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <!-- birthday and anniversary (not necessarily the same) -->\n"
-" <field name=\"BDAY\" type=\"date\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"ANNIVERSARY\" type=\"date\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <!-- telephone numbers -->\n"
-" <field name=\"TEL\" array=\"yes\" type=\"telephone\" compare=\"conflict\"/>\n"
-" <field name=\"TEL_FLAGS\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 0 -->\n"
-" <field name=\"TEL_LABEL\" array=\"yes\" type=\"string\" compare=\"conflict\"/> <!-- offset 1 -->\n"
-" <field name=\"TEL_ID\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 2 -->\n"
-" <field name=\"TEL_SLOT\" array=\"yes\" type=\"integer\" compare=\"never\"/> <!-- offset 3 -->\n"
-"\n"
-" <!-- emails -->\n"
-" <field name=\"EMAIL\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"EMAIL_FLAGS\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 0 -->\n"
-" <field name=\"EMAIL_LABEL\" array=\"yes\" type=\"string\" compare=\"conflict\"/> <!-- offset 1 -->\n"
-" <field name=\"EMAIL_ID\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 2 -->\n"
-" <field name=\"EMAIL_SLOT\" array=\"yes\" type=\"integer\" compare=\"never\"/> <!-- offset 3 -->\n"
-"\n"
-" <!-- web addresses -->\n"
-" <field name=\"WEB\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"WEB_FLAGS\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 0 -->\n"
-" <field name=\"WEB_LABEL\" array=\"yes\" type=\"string\" compare=\"conflict\"/> <!-- offset 1 -->\n"
-" <field name=\"WEB_ID\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 2 -->\n"
-"\n"
-" <!-- would be nicer to have as part of WEB, but parser/encoder does not support mapping\n"
-" with more than one property per field -->\n"
-" <field name=\"CALURI\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"FBURL\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"BLOGURL\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"VIDEOURL\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- related persons: should be turned into array, like WEB and CALURI/FBURL -->\n"
-" <field name=\"MANAGER\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ASSISTANT\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"SPOUSE\" type=\"string\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- does this person want HTML mails? Valid values are TRUE/FALSE; a \"boolean\"\n"
-" type would be useful, maybe add that later. -->\n"
-" <field name=\"WANTS_HTML\" type=\"string\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- chat handles: should be turned into one array, like WEB and CALURI/FBURL -->\n"
-" <field name=\"AIM_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"AIM_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"GADUGADU_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"GADUGADU_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"GROUPWISE_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"GROUPWISE_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ICQ_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ICQ_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"JABBER_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"JABBER_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"MSN_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"MSN_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"YAHOO_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"YAHOO_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"SKYPE_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"SKYPE_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"SIP_HANDLE\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"SIP_SLOT\" array=\"yes\" type=\"string\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- home address -->\n"
-" <field name=\"ADR_STREET\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"ADR_ADDTL\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"ADR_STREET_FLAGS\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 0 (from ADR_STREET_FLAGS) -->\n"
-" <field name=\"ADR_STREET_LABEL\" array=\"yes\" type=\"string\" compare=\"conflict\"/> <!-- offset 1 -->\n"
-" <field name=\"ADR_STREET_ID\" array=\"yes\" type=\"integer\" compare=\"conflict\"/> <!-- offset 2 -->\n"
-" <field name=\"ADR_POBOX\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"ADR_CITY\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"ADR_REG\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"ADR_ZIP\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-" <field name=\"ADR_COUNTRY\" array=\"yes\" type=\"multiline\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- Note -->\n"
-" <field name=\"NOTE\" type=\"multiline\" compare=\"conflict\" merge=\"lines\"/>\n"
-"\n"
-" <!-- Photo -->\n"
-" <field name=\"PHOTO\" type=\"blob\" compare=\"never\" merge=\"fillempty\"/>\n"
-" <field name=\"PHOTO_TYPE\" type=\"integer\" compare=\"never\" merge=\"fillempty\"/>\n"
-"\n"
-" </fieldlist>\n"
-"\n"
-" <!-- vCard profile -->\n"
-" <mimeprofile name=\"vCard\" fieldlist=\"contacts\">\n"
-"\n"
-" <profile name=\"VCARD\" nummandatory=\"0\"> <!-- we allow records without \"N\" as Address book can store them -->\n"
-" <property name=\"VERSION\">\n"
-" <value conversion=\"version\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"standard\" name=\"PRODID\" mandatory=\"no\">\n"
-" <value conversion=\"prodid\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"REV\">\n"
-" <value field=\"REV\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"N\" values=\"5\" mandatory=\"yes\"> <!-- Note: makes N parse and generate even if not in remote's CTCap -->\n"
-" <value index=\"0\" field=\"N_LAST\"/>\n"
-" <value index=\"1\" field=\"N_FIRST\"/>\n"
-" <value index=\"2\" field=\"N_MIDDLE\"/>\n"
-" <value index=\"3\" field=\"N_PREFIX\"/>\n"
-" <value index=\"4\" field=\"N_SUFFIX\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"FN\">\n"
-" <value field=\"FN\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-EVOLUTION-FILE-AS\">\n"
-" <value field=\"FILE-AS\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-GENDER\">\n"
-" <value field=\"GENDER\"/>\n"
-" </property>\n"
-"\n"
-" <!-- onlyformode=\"standard\": not part of vCard 2.1, but some\n"
-" peers (like the Funambol server) accept it anyway in\n"
-" vCard 2.1 -->\n"
-" <property name=\"NICKNAME\">\n"
-" <value field=\"NICKNAME\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"TITLE\">\n"
-" <value field=\"TITLE\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"CATEGORIES\" values=\"list\" valueseparator=\",\" altvalueseparator=\";\" > <!-- non-standard, but 1:1 as in vCard 3.0 (NOT like in vCalendar 1.0, where separator is \";\") -->\n"
-" <value field=\"CATEGORIES\"/>\n"
-" <position field=\"CATEGORIES\" repeat=\"array\" increment=\"1\" minshow=\"0\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"ORG\" values=\"4\">\n"
-" <value index=\"0\" field=\"ORG_NAME\"/>\n"
-" <value index=\"1\" field=\"ORG_DIVISION\"/>\n"
-" <value index=\"2\" field=\"ORG_OFFICE\"/>\n"
-" <value index=\"3\" field=\"ORG_TEAM\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"ROLE\">\n"
-" <value field=\"ROLE\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"TEL\">\n"
-" <value field=\"TEL\"/>\n"
-" <position field=\"TEL\" repeat=\"array\" increment=\"1\" minshow=\"1\"/>\n"
-" <parameter name=\"TYPE\" default=\"yes\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"TEL_FLAGS\" conversion=\"multimix\" combine=\",\">\n"
-" <enum name=\"HOME\" value=\"B0\"/>\n"
-" <enum name=\"WORK\" value=\"B1\"/>\n"
-" <enum mode=\"ignore\" value=\"B2\"/> <!-- OTHER -->\n"
-" <enum name=\"VOICE\" value=\"B3\"/>\n"
-" <enum name=\"CELL\" value=\"B4\"/>\n"
-" <enum name=\"FAX\" value=\"B5\"/>\n"
-" <enum name=\"PAGER\" value=\"B6\"/>\n"
-" <enum name=\"PREF\" value=\"B7\"/>\n"
-" <enum name=\"CAR\" value=\"B8\"/>\n"
-" <enum name=\"X-EVOLUTION-CALLBACK\" value=\"B9\"/>\n"
-" <enum name=\"X-EVOLUTION-RADIO\" value=\"B10\"/>\n"
-" <enum name=\"X-EVOLUTION-TELEX\" value=\"B11\"/>\n"
-" <enum name=\"X-EVOLUTION-TTYTDD\" value=\"B12\"/>\n"
-"\n"
-" <enum mode=\"prefix\" name=\"X-CustomLabel-\" value=\"1.L\"/>\n"
-" <enum mode=\"prefix\" name=\"X-Synthesis-Ref\" value=\"2.L\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"TEL_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"EMAIL\">\n"
-" <value field=\"EMAIL\"/>\n"
-" <position field=\"EMAIL\" repeat=\"array\" increment=\"1\" minshow=\"1\"/>\n"
-" <parameter name=\"TYPE\" default=\"yes\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"EMAIL_FLAGS\" conversion=\"multimix\" combine=\",\">\n"
-" <enum name=\"HOME\" value=\"B0\"/>\n"
-" <enum name=\"WORK\" value=\"B1\"/>\n"
-" <enum mode=\"ignore\" value=\"B2\"/> <!-- OTHER -->\n"
-" <enum name=\"INTERNET\" value=\"B3\"/>\n"
-"\n"
-" <enum mode=\"prefix\" name=\"X-CustomLabel-\" value=\"1.L\"/>\n"
-" <enum mode=\"prefix\" name=\"X-Synthesis-Ref\" value=\"2.L\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"EMAIL_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"URL\">\n"
-" <value field=\"WEB\"/>\n"
-" <position field=\"WEB\" repeat=\"array\" increment=\"1\" minshow=\"1\"/>\n"
-" <parameter name=\"TYPE\" default=\"yes\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"WEB_FLAGS\" conversion=\"multimix\" combine=\",\">\n"
-" <enum name=\"HOME\" value=\"B0\"/>\n"
-" <enum name=\"WORK\" value=\"B1\"/>\n"
-" <enum mode=\"ignore\" value=\"B2\"/> <!-- OTHER -->\n"
-" <enum name=\"PREF\" value=\"B3\"/>\n"
-"\n"
-" <enum mode=\"prefix\" name=\"X-CustomLabel-\" value=\"1.L\"/>\n"
-" <enum mode=\"prefix\" name=\"X-Synthesis-Ref\" value=\"2.L\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"CALURI\" suppressempty=\"yes\">\n"
-" <value field=\"CALURI\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"FBURL\" suppressempty=\"yes\">\n"
-" <value field=\"FBURL\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"X-EVOLUTION-BLOG-URL\" suppressempty=\"yes\">\n"
-" <value field=\"BLOGURL\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"X-EVOLUTION-VIDEO-URL\" suppressempty=\"yes\">\n"
-" <value field=\"VIDEOURL\" show=\"yes\"/>\n"
-" </property>\n"
-"\n"
-" <!-- item for SyncML server: EVOLUTION rule not active,\n"
-" both X-EVOLUTION-MANAGER and X-MANAGER are sent.\n"
-"\n"
-" item from SyncML server: EVOLUTION rule not active,\n"
-" both X-EVOLUTION-MANAGER and X-MANAGER are checked,\n"
-" but X-EVOLUTION-MANAGER later so that it overwrites\n"
-" a value set earlier by X-MANAGER (if any). This is\n"
-" a more or less arbitrary priority, chosen because\n"
-" servers that know about SyncEvolution (ScheduleWorld,\n"
-" Memotoo) use the X-EVOLUTION variant.\n"
-"\n"
-" item to/from Evolution: EVOLUTION rule is active,\n"
-" only X-EVOLUTION-MANAGER is used. -->\n"
-" <property name=\"X-EVOLUTION-MANAGER\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"MANAGER\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"X-MANAGER\" suppressempty=\"yes\" rule=\"EVOLUTION\"/> <!-- disables the X-MANAGER for EVOLUTION -->\n"
-" <property name=\"X-MANAGER\" suppressempty=\"yes\" rule=\"other\">\n"
-" <value field=\"MANAGER\" show=\"yes\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-EVOLUTION-ASSISTANT\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"ASSISTANT\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"X-ASSISTANT\" suppressempty=\"yes\" rule=\"EVOLUTION\"/>\n"
-" <property name=\"X-ASSISTANT\" suppressempty=\"yes\" rule=\"other\">\n"
-" <value field=\"ASSISTANT\" show=\"yes\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-EVOLUTION-SPOUSE\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"SPOUSE\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"X-SPOUSE\" suppressempty=\"yes\" rule=\"EVOLUTION\"/>\n"
-" <property name=\"X-SPOUSE\" suppressempty=\"yes\" rule=\"other\">\n"
-" <value field=\"SPOUSE\" show=\"yes\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-EVOLUTION-ANNIVERSARY\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"ANNIVERSARY\" show=\"yes\"/>\n"
-" </property>\n"
-" <property name=\"X-ANNIVERSARY\" suppressempty=\"yes\" rule=\"EVOLUTION\"/>\n"
-" <property name=\"X-ANNIVERSARY\" suppressempty=\"yes\" rule=\"other\">\n"
-" <value field=\"ANNIVERSARY\" show=\"yes\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-MOZILLA-HTML\">\n"
-" <value field=\"WANTS_HTML\" show=\"yes\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-AIM\" suppressempty=\"yes\">\n"
-" <value field=\"AIM_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"AIM_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"X-GADUGADU\" suppressempty=\"yes\">\n"
-" <value field=\"GADUGADU_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"GADUGADU_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"X-GROUPWISE\" suppressempty=\"yes\">\n"
-" <value field=\"GROUPWISE_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"GROUPWISE_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"X-ICQ\" suppressempty=\"yes\">\n"
-" <value field=\"ICQ_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"ICQ_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"X-JABBER\" suppressempty=\"yes\">\n"
-" <value field=\"JABBER_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"JABBER_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"X-MSN\" suppressempty=\"yes\">\n"
-" <value field=\"MSN_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"MSN_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"X-YAHOO\" suppressempty=\"yes\">\n"
-" <value field=\"YAHOO_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"YAHOO_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-SKYPE\" suppressempty=\"yes\"> \n"
-" <value field=\"SKYPE_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"SKYPE_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-SIP\" suppressempty=\"yes\">\n"
-" <value field=\"SIP_HANDLE\"/>\n"
-" <parameter name=\"X-EVOLUTION-UI-SLOT\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"SIP_SLOT\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"ADR\" values=\"7\">\n"
-" <value index=\"0\" field=\"ADR_POBOX\"/>\n"
-" <value index=\"1\" field=\"ADR_ADDTL\"/>\n"
-" <value index=\"2\" field=\"ADR_STREET\"/>\n"
-" <value index=\"3\" field=\"ADR_CITY\"/>\n"
-" <value index=\"4\" field=\"ADR_REG\"/>\n"
-" <value index=\"5\" field=\"ADR_ZIP\"/>\n"
-" <value index=\"6\" field=\"ADR_COUNTRY\"/>\n"
-" <position field=\"ADR_POBOX\" repeat=\"array\" increment=\"1\" minshow=\"1\"/>\n"
-" <parameter name=\"TYPE\" default=\"yes\" positional=\"no\" show=\"yes\">\n"
-" <value field=\"ADR_STREET_FLAGS\" conversion=\"multimix\" combine=\",\">\n"
-" <enum name=\"HOME\" value=\"B0\"/>\n"
-" <enum name=\"WORK\" value=\"B1\"/>\n"
-" <enum mode=\"ignore\" value=\"B2\"/> <!-- OTHER -->\n"
-"\n"
-" <enum mode=\"prefix\" name=\"X-CustomLabel-\" value=\"1.L\"/>\n"
-" <enum mode=\"prefix\" name=\"X-Synthesis-Ref\" value=\"2.L\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"BDAY\">\n"
-" <value field=\"BDAY\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"NOTE\" filter=\"no\">\n"
-" <value field=\"NOTE\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"PHOTO\" filter=\"no\">\n"
-" <value field=\"PHOTO\" conversion=\"BLOB_B64\"/>\n"
-" <parameter name=\"TYPE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"PHOTO_TYPE\">\n"
-" <enum name=\"JPEG\" value=\"0\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" </profile>\n"
-" </mimeprofile>\n"
-"\n"
-" <!-- vCard 2.1 datatype, using vCard profile defined above -->\n"
-" <datatype name=\"vCard21\" basetype=\"vcard\">\n"
-" <version>2.1</version>\n"
-" <use mimeprofile=\"vCard\"/>\n"
-" <incomingscript><![CDATA[\n"
-" $VCARD_INCOMING_NAMECHANGE_SCRIPT\n"
-" ]]></incomingscript>\n"
-" </datatype>\n"
-"\n"
-" <!-- vCard 3.0 datatype, using vCard profile defined above -->\n"
-" <datatype name=\"vCard30\" basetype=\"vcard\">\n"
-" <version>3.0</version>\n"
-" <use mimeprofile=\"vCard\"/>\n"
-" <incomingscript><![CDATA[\n"
-" $VCARD_INCOMING_NAMECHANGE_SCRIPT\n"
-" ]]></incomingscript>\n"
-" </datatype>\n"
-"\n"
-"\n"
-" <!-- common field list for events and todos (both represented by vCalendar/iCalendar) -->\n"
-" <fieldlist name=\"calendar\">\n"
-" <field name=\"ISEVENT\" type=\"integer\" compare=\"always\"/>\n"
-"\n"
-" <field name=\"DMODIFIED\" type=\"timestamp\" compare=\"never\" age=\"yes\"/>\n"
-" <field name=\"DCREATED\" type=\"timestamp\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"DGENERATED\" type=\"timestamp\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"UID\" type=\"string\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"CATEGORIES\" array=\"yes\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"CLASS\" type=\"integer\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"TRANSP\" type=\"integer\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <field name=\"SUMMARY\" type=\"multiline\" compare=\"always\"/>\n"
-" <field name=\"DESCRIPTION\" type=\"multiline\" compare=\"slowsync\" merge=\"lines\"/>\n"
-" <field name=\"LOCATION\" type=\"multiline\" compare=\"slowsync\" merge=\"lines\"/>\n"
-" <field name=\"URL\" type=\"url\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- recurrence rule block, fields must be in that order, including\n"
-" DTSTART as last field !! -->\n"
-" <field name=\"RR_FREQ\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"RR_INTERVAL\" type=\"integer\" compare=\"conflict\"/>\n"
-" <field name=\"RR_FMASK\" type=\"integer\" compare=\"conflict\"/>\n"
-" <field name=\"RR_LMASK\" type=\"integer\" compare=\"conflict\"/>\n"
-" <field name=\"RR_END\" type=\"timestamp\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- Note: DTSTART/DTEND are compared in the <comparescript>,\n"
-" therefore compare is set no \"never\" here -->\n"
-" <field name=\"DTSTART\" type=\"timestamp\" compare=\"never\"/>\n"
-" <field name=\"DTEND\" type=\"timestamp\" compare=\"never\"/>\n"
-" <field name=\"DURATION\" type=\"timestamp\" compare=\"never\"/>\n"
-" <field name=\"COMPLETED\" type=\"timestamp\" compare=\"never\"/>\n"
-" <field name=\"DUE\" type=\"timestamp\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"GEO_LAT\" type=\"string\" compare=\"never\"/>\n"
-" <field name=\"GEO_LONG\" type=\"string\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"PRIORITY\" type=\"integer\" compare=\"conflict\"/>\n"
-" <field name=\"STATUS\" type=\"integer\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"PERCENT_COMPLETE\" type=\"integer\" compare=\"conflict\"/>\n"
-"\n"
-" <field name=\"ALARM_TIME\" type=\"timestamp\" compare=\"conflict\"/>\n"
-" <field name=\"ALARM_SNOOZE\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ALARM_REPEAT\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ALARM_MSG\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ALARM_ACTION\" type=\"string\" compare=\"conflict\"/>\n"
-" <field name=\"ALARM_REL\" type=\"integer\" compare=\"never\"/>\n"
-" <field name=\"ALARM_UID\" type=\"string\" compare=\"conflict\"/>\n"
-"\n"
-" <!-- non-standard -->\n"
-" <field name=\"PARENT_UID\" type=\"string\" compare=\"never\"/>\n"
-"\n"
-" <!-- for events -->\n"
-" <field name=\"EXDATES\" array=\"yes\" type=\"timestamp\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"ORIGSTART\" array=\"no\" type=\"timestamp\" compare=\"never\"/>\n"
-" <field name=\"SEQNO\" array=\"no\" type=\"integer\" compare=\"never\"/>\n"
-"\n"
-" <field name=\"ATTENDEES\" array=\"yes\" type=\"string\" compare=\"never\"/>\n"
-" <field name=\"ATTENDEE_CNS\" array=\"yes\" type=\"string\" compare=\"never\"/>\n"
-" <field name=\"ATTENDEE_PARTSTATS\" array=\"yes\" type=\"integer\" compare=\"never\"/>\n"
-" <field name=\"ATTENDEE_ROLE\" array=\"yes\" type=\"integer\" compare=\"never\"/>\n"
-" <field name=\"ATTENDEE_RSVP\" array=\"yes\" type=\"integer\" compare=\"never\"/>\n"
-" <field name=\"ATTENDEE_LANG\" array=\"yes\" type=\"string\" compare=\"never\"/>\n"
-" <field name=\"ATTENDEE_CUTYPE\" array=\"yes\" type=\"integer\" compare=\"never\"/>\n"
-" <field name=\"ORGANIZER\" array=\"no\" type=\"string\" compare=\"never\"/>\n"
-" <field name=\"ORGANIZER_CN\" array=\"no\" type=\"string\" compare=\"never\"/>\n"
-"\n"
-" </fieldlist>\n"
-"\n"
-"\n"
-" <!-- vCalendar with VTODO and VEVENT variants -->\n"
-" <mimeprofile name=\"vCalendar\" fieldlist=\"calendar\">\n"
-"\n"
-" <vtimezonegenmode>current</vtimezonegenmode>\n"
-" <tzidgenmode>olson</tzidgenmode>\n"
-"\n"
-" <profile name=\"VCALENDAR\" nummandatory=\"1\">\n"
-"\n"
-" <property name=\"VERSION\" mandatory=\"yes\">\n"
-" <value conversion=\"version\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"standard\" name=\"PRODID\" mandatory=\"no\">\n"
-" <value conversion=\"prodid\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"old\" name=\"TZ\" filter=\"false\" suppressempty=\"yes\">\n"
-" <value field=\"DTSTART\" conversion=\"tz\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"old\" name=\"DAYLIGHT\" mode=\"daylight\" filter=\"false\" suppressempty=\"yes\">\n"
-" <value field=\"DTSTART\" conversion=\"daylight\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"GEO\" values=\"2\" suppressempty=\"yes\" onlyformode=\"old\" valueseparator=\",\">\n"
-" <!-- LON,LAT in vCalendar 1.0 -->\n"
-" <value index=\"0\" field=\"GEO_LAT\"/>\n"
-" <value index=\"1\" field=\"GEO_LONG\"/>\n"
-" </property>\n"
-"\n"
-" <subprofile onlyformode=\"standard\" name=\"VTIMEZONE\" mode=\"vtimezones\"/>\n"
-"\n"
-" <!-- sub-profile for todoz -->\n"
-" <subprofile name=\"VTODO\" nummandatory=\"1\" showifselectedonly=\"yes\" field=\"ISEVENT\" value=\"0\">\n"
-"\n"
-" <property name=\"LAST-MODIFIED\" suppressempty=\"yes\">\n"
-" <value field=\"DMODIFIED\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"DTSTAMP\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"DGENERATED\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"DCREATED\" suppressempty=\"yes\" onlyformode=\"old\">\n"
-" <value field=\"DCREATED\"/>\n"
-" </property>\n"
-" <property name=\"CREATED\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"DCREATED\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"UID\" suppressempty=\"yes\">\n"
-" <value field=\"UID\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"SEQUENCE\" suppressempty=\"yes\">\n"
-" <value field=\"SEQNO\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"GEO\" values=\"2\" suppressempty=\"yes\" onlyformode=\"standard\" valueseparator=\";\">\n"
-" <!-- LAT;LON in iCalendar 2.0 -->\n"
-" <value index=\"0\" field=\"GEO_LONG\"/>\n"
-" <value index=\"1\" field=\"GEO_LAT\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"standard\" name=\"CATEGORIES\" values=\"list\" valueseparator=\",\" suppressempty=\"yes\">\n"
-" <value field=\"CATEGORIES\" />\n"
-" <position field=\"CATEGORIES\" repeat=\"array\" minshow=\"0\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"old\" name=\"CATEGORIES\" values=\"list\" valueseparator=\";\" altvalueseparator=\",\" suppressempty=\"yes\">\n"
-" <value field=\"CATEGORIES\" />\n"
-" <position field=\"CATEGORIES\" repeat=\"array\" minshow=\"0\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"CLASS\" suppressempty=\"yes\">\n"
-" <value field=\"CLASS\">\n"
-" <enum name=\"PUBLIC\" value=\"0\"/>\n"
-" <enum name=\"PRIVATE\" value=\"1\"/>\n"
-" <enum name=\"CONFIDENTIAL\" value=\"2\"/>\n"
-" </value>\n"
-" </property>\n"
-"\n"
-" <property name=\"SUMMARY\" mandatory=\"yes\">\n"
-" <value field=\"SUMMARY\"/>\n"
-" </property>\n"
-"\n"
-" <!-- DESCRIPTION is an optional property and libical does not like\n"
-" empty properties, so suppress it here. However, in the scripts\n"
-" we ensure that the DESCRIPTION field should never be empty. -->\n"
-" <property name=\"DESCRIPTION\" suppressempty=\"yes\" mandatory=\"no\">\n"
-" <value field=\"DESCRIPTION\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"LOCATION\" suppressempty=\"yes\" mandatory=\"no\">\n"
-" <value field=\"LOCATION\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"URL\" suppressempty=\"yes\" mandatory=\"no\">\n"
-" <value field=\"URL\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"DTSTART\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"DTSTART\" conversion=\"autodate\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DTSTART\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" <parameter onlyformode=\"standard\" name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DTSTART\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"COMPLETED\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"COMPLETED\" conversion=\"autoenddate\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"COMPLETED\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" <parameter onlyformode=\"standard\" name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"COMPLETED\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"DUE\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"DUE\" conversion=\"autodate\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DUE\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" <parameter onlyformode=\"standard\" name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DUE\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"PRIORITY\" suppressempty=\"yes\">\n"
-" <value field=\"PRIORITY\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"STATUS\" onlyformode=\"standard\" suppressempty=\"yes\">\n"
-" <value field=\"STATUS\" conversion=\"emptyonly\">\n"
-" <enum name=\"COMPLETED\" value=\"0\"/>\n"
-" <enum name=\"NEEDS-ACTION\" value=\"1\"/>\n"
-" <enum name=\"IN-PROCESS\" value=\"2\"/>\n"
-" <enum name=\"CANCELLED\" value=\"3\"/>\n"
-" <enum name=\"ACCEPTED\" value=\"4\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"5\"/>\n"
-" <enum name=\"DELEGATED\" value=\"6\"/>\n"
-" <enum name=\"DECLINED\" value=\"7\"/>\n"
-" <enum name=\"SENT\" value=\"8\"/>\n"
-" <enum name=\"CONFIRMED\" value=\"9\"/>\n"
-" <enum name=\"DRAFT\" value=\"10\"/>\n"
-" <enum name=\"FINAL\" value=\"11\"/>\n"
-" </value>\n"
-" </property>\n"
-"\n"
-" <property name=\"STATUS\" onlyformode=\"old\" suppressempty=\"yes\">\n"
-" <value field=\"STATUS\" conversion=\"emptyonly\">\n"
-" <enum name=\"COMPLETED\" value=\"0\"/>\n"
-" <enum name=\"NEEDS ACTION\" value=\"1\"/>\n"
-" <enum mode=\"defaultvalue\" value=\"1\"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->\n"
-" <enum name=\"IN PROCESS\" value=\"2\"/>\n"
-" <enum name=\"CANCELLED\" value=\"3\"/>\n"
-" <enum name=\"ACCEPTED\" value=\"4\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"5\"/>\n"
-" <enum name=\"DELEGATED\" value=\"6\"/>\n"
-" <enum name=\"DECLINED\" value=\"7\"/>\n"
-" <enum name=\"SENT\" value=\"8\"/>\n"
-" <enum name=\"CONFIRMED\" value=\"9\"/>\n"
-" <enum name=\"DRAFT\" value=\"10\"/>\n"
-" <enum name=\"FINAL\" value=\"11\"/>\n"
-" </value>\n"
-" </property>\n"
-"\n"
-" <property name=\"PERCENT-COMPLETE\" onlyformode=\"standard\" suppressempty=\"yes\">\n"
-" <value field=\"PERCENT_COMPLETE\"/>\n"
-" </property> \n"
-"\n"
-" <!-- AALARM and DALARM both use the same fields -->\n"
-" <property name=\"AALARM\" onlyformode=\"old\" values=\"4\" suppressempty=\"yes\">\n"
-" <value index=\"0\" field=\"ALARM_TIME\" conversion=\"emptyonly\"/>\n"
-" <value index=\"1\" field=\"ALARM_SNOOZE\" conversion=\"emptyonly\"/>\n"
-" <value index=\"2\" field=\"ALARM_REPEAT\" conversion=\"emptyonly\"/>\n"
-" <value index=\"3\" field=\"ALARM_MSG\" conversion=\"emptyonly\"/>\n"
-" </property>\n"
-" <property name=\"DALARM\" onlyformode=\"old\" values=\"4\" suppressempty=\"yes\">\n"
-" <value index=\"0\" field=\"ALARM_TIME\" conversion=\"emptyonly\"/>\n"
-" <value index=\"1\" field=\"ALARM_SNOOZE\" conversion=\"emptyonly\"/>\n"
-" <value index=\"2\" field=\"ALARM_REPEAT\" conversion=\"emptyonly\"/>\n"
-" <value index=\"3\" field=\"ALARM_MSG\" conversion=\"emptyonly\"/>\n"
-" </property>\n"
-"\n"
-" <subprofile onlyformode=\"standard\" name=\"VALARM\" nummandatory=\"1\" field=\"ALARM_TIME\">\n"
-" <property name=\"TRIGGER\" suppressempty=\"no\" mandatory=\"yes\">\n"
-" <value field=\"ALARM_TIME\"/>\n"
-" <parameter name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ALARM_TIME\" conversion=\"FULLVALUETYPE\"/>\n"
-" </parameter>\n"
-" <parameter name=\"RELATED\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ALARM_REL\">\n"
-" <enum mode=\"ignore\" value=\"0\"/>\n"
-" <enum name=\"START\" value=\"1\"/>\n"
-" <enum name=\"END\" value=\"2\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"ACTION\" suppressempty=\"yes\" mandatory=\"yes\">\n"
-" <value field=\"ALARM_ACTION\"/>\n"
-" </property>\n"
-" <property name=\"DESCRIPTION\" suppressempty=\"yes\">\n"
-" <value field=\"ALARM_MSG\"/>\n"
-" </property>\n"
-" <property name=\"REPEAT\" suppressempty=\"yes\">\n"
-" <value field=\"ALARM_REPEAT\"/>\n"
-" </property>\n"
-" <property name=\"X-EVOLUTION-ALARM-UID\" suppressempty=\"yes\">\n"
-" <value field=\"ALARM_UID\"/>\n"
-" </property>\n"
-" </subprofile>\n"
-"\n"
-" <property onlyformode=\"old\" name=\"RELATED-TO\" suppressempty=\"yes\">\n"
-" <value field=\"PARENT_UID\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"standard\" name=\"RELATED-TO\" suppressempty=\"yes\">\n"
-" <value field=\"PARENT_UID\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"RELTYPE\" default=\"no\" positional=\"yes\" show=\"yes\">\n"
-" <value>\n"
-" <enum name=\"PARENT\"/>\n"
-" <enum mode=\"defaultvalue\" name=\"other\"/>\n"
-" </value>\n"
-" <position hasnot=\"other\" shows=\"PARENT\" field=\"PARENT_UID\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" </subprofile>\n"
-"\n"
-" <!-- sub-profile for event -->\n"
-" <subprofile name=\"VEVENT\" nummandatory=\"1\" showifselectedonly=\"yes\" field=\"ISEVENT\" value=\"1\">\n"
-"\n"
-" <property name=\"STATUS\" suppressempty=\"yes\" onlyformode=\"old\">\n"
-" <value field=\"STATUS\" conversion=\"emptyonly\">\n"
-" <enum name=\"COMPLETED\" value=\"0\"/>\n"
-" <enum mode=\"defaultvalue\" value=\"1\"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->\n"
-" <enum name=\"NEEDS ACTION\" value=\"1\"/>\n"
-" <enum name=\"CANCELLED\" value=\"3\"/>\n"
-" <enum name=\"ACCEPTED\" value=\"4\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"5\"/>\n"
-" <enum name=\"DELEGATED\" value=\"6\"/>\n"
-" <enum name=\"DECLINED\" value=\"7\"/>\n"
-" <enum name=\"SENT\" value=\"8\"/>\n"
-" <enum name=\"CONFIRMED\" value=\"9\"/>\n"
-" <enum name=\"FINAL\" value=\"11\"/>\n"
-" </value>\n"
-" </property>\n"
-"\n"
-" <property name=\"STATUS\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"STATUS\" conversion=\"emptyonly\">\n"
-" <enum name=\"CANCELLED\" value=\"3\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"5\"/>\n"
-" <enum name=\"CONFIRMED\" value=\"9\"/>\n"
-" </value>\n"
-" </property>\n"
-"\n"
-" <property name=\"LAST-MODIFIED\" suppressempty=\"yes\">\n"
-" <value field=\"DMODIFIED\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"DTSTAMP\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"DGENERATED\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"DCREATED\" suppressempty=\"yes\" onlyformode=\"old\">\n"
-" <value field=\"DCREATED\"/>\n"
-" </property>\n"
-" <property name=\"CREATED\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"DCREATED\"/>\n"
-" </property>\n"
-"\n"
-"\n"
-" <property name=\"UID\" suppressempty=\"yes\">\n"
-" <value field=\"UID\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"SEQUENCE\" suppressempty=\"yes\">\n"
-" <value field=\"SEQNO\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"GEO\" values=\"2\" suppressempty=\"yes\" onlyformode=\"standard\" valueseparator=\";\">\n"
-" <!-- LAT;LON in iCalendar 2.0 -->\n"
-" <value index=\"0\" field=\"GEO_LONG\"/>\n"
-" <value index=\"1\" field=\"GEO_LAT\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"standard\" name=\"CATEGORIES\" values=\"list\" valueseparator=\",\" suppressempty=\"yes\">\n"
-" <value field=\"CATEGORIES\" />\n"
-" <position field=\"CATEGORIES\" repeat=\"array\" minshow=\"0\"/>\n"
-" </property>\n"
-"\n"
-" <property onlyformode=\"old\" name=\"CATEGORIES\" values=\"list\" valueseparator=\";\" altvalueseparator=\",\" suppressempty=\"yes\">\n"
-" <value field=\"CATEGORIES\" />\n"
-" <position field=\"CATEGORIES\" repeat=\"array\" minshow=\"0\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"CLASS\" suppressempty=\"yes\">\n"
-" <value field=\"CLASS\">\n"
-" <enum name=\"PUBLIC\" value=\"0\"/>\n"
-" <enum name=\"PRIVATE\" value=\"1\"/>\n"
-" <enum name=\"CONFIDENTIAL\" value=\"2\"/>\n"
-" </value>\n"
-" </property>\n"
-"\n"
-"\n"
-" <property name=\"TRANSP\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"TRANSP\">\n"
-" <enum name=\"OPAQUE\" value=\"0\"/>\n"
-" <enum name=\"TRANSPARENT\" value=\"1\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"2\"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->\n"
-" <enum name=\"OUT_OF_OFFICE\" value=\"3\"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->\n"
-" <enum mode=\"defaultvalue\" value=\"0\"/>\n"
-" </value>\n"
-" </property>\n"
-" <property name=\"TRANSP\" suppressempty=\"yes\" onlyformode=\"old\">\n"
-" <value field=\"TRANSP\"/> <!-- directly numeric in vCalendar 1.0 -->\n"
-" </property>\n"
-"\n"
-"\n"
-" <property name=\"PRIORITY\" suppressempty=\"yes\">\n"
-" <value field=\"PRIORITY\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"SUMMARY\" mandatory=\"yes\">\n"
-" <value field=\"SUMMARY\"/>\n"
-" </property>\n"
-"\n"
-" <!-- DESCRIPTION is an optional property and libical does not like\n"
-" empty properties, so suppress it here. However, in the scripts\n"
-" we ensure that the DESCRIPTION field should never be empty. -->\n"
-" <property name=\"DESCRIPTION\" suppressempty=\"yes\" mandatory=\"no\">\n"
-" <value field=\"DESCRIPTION\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"LOCATION\" suppressempty=\"yes\" mandatory=\"no\">\n"
-" <value field=\"LOCATION\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"DTSTART\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"DTSTART\" conversion=\"autodate\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DTSTART\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" <parameter onlyformode=\"standard\" name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DTSTART\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <!-- recurrence rule (with delayed parsing, as it is dependent on DTSTART) -->\n"
-" <property name=\"RRULE\" suppressempty=\"yes\" delayedparsing=\"2\">\n"
-" <!-- Note: RR_FREQ is the beginning of a block of fields\n"
-" suitable for the \"rrule\" conversion mode -->\n"
-" <value field=\"RR_FREQ\" conversion=\"rrule\"/>\n"
-" </property>\n"
-"\n"
-" <!-- Symbian uses this, so it might make the client work with symbian-prepared servers better -->\n"
-" <property name=\"X-RECURRENCE-ID\" suppressempty=\"yes\" onlyformode=\"old\">\n"
-" <value field=\"ORIGSTART\" conversion=\"autodate\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"RECURRENCE-ID\" suppressempty=\"yes\" onlyformode=\"standard\" delayedparsing=\"1\">\n"
-" <value field=\"ORIGSTART\" conversion=\"autodate\"/>\n"
-" <parameter name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ORIGSTART\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" <parameter name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ORIGSTART\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <!-- ScheduleWorld has a problem (bugzilla.moblin.org #2226)\n"
-" with the EXDATE:value1,value2 format (correct in iCalendar 2.0):\n"
-" as a workaround, accept all valid formats plus ; but\n"
-" generate separate properties with one value each. -->\n"
-" <property name=\"EXDATE\" values=\"expandedlist\" suppressempty=\"yes\" onlyformode=\"standard\" delayedparsing=\"1\" valueseparator=\",\" altvalueseparator=\";\">\n"
-" <value field=\"EXDATES\"/>\n"
-" <position field=\"EXDATES\" repeat=\"array\" increment=\"1\" minshow=\"0\"/>\n"
-" <parameter name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"EXDATES\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"EXDATE\" values=\"list\" suppressempty=\"yes\" onlyformode=\"old\" delayedparsing=\"1\" valueseparator=\";\" altvalueseparator=\",\">\n"
-" <value field=\"EXDATES\"/>\n"
-" <position field=\"EXDATES\" repeat=\"array\" increment=\"1\" minshow=\"0\"/>\n"
-" </property>\n"
-"\n"
-"\n"
-" <property name=\"DTEND\" suppressempty=\"yes\" delayedparsing=\"1\">\n"
-" <value field=\"DTEND\" conversion=\"autoenddate\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"TZID\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DTEND\" conversion=\"TZID\"/>\n"
-" </parameter>\n"
-" <parameter onlyformode=\"standard\" name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"DTEND\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"DURATION\" suppressempty=\"yes\" delayedparsing=\"1\" onlyformode=\"standard\">\n"
-" <value field=\"DURATION\"/>\n"
-" <parameter onlyformode=\"standard\" name=\"VALUE\" default=\"no\" show=\"no\">\n"
-" <value field=\"DURATION\" conversion=\"VALUETYPE\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"ATTENDEE\" suppressempty=\"yes\" onlyformode=\"old\">\n"
-" <value field=\"ATTENDEES\"/>\n"
-" <parameter name=\"ROLE\" default=\"no\" positional=\"yes\" show=\"yes\">\n"
-" <value>\n"
-" <enum name=\"ORGANIZER\"/>\n"
-" </value>\n"
-" <position has=\"ORGANIZER\" field=\"ORGANIZER\" overwriteempty=\"yes\"/>\n"
-" <position hasnot=\"ORGANIZER\" field=\"ATTENDEES\" repeat=\"array\" increment=\"1\" overwriteempty=\"yes\"/>\n"
-" </parameter>\n"
-" <parameter name=\"STATUS\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ATTENDEE_PARTSTATS\">\n"
-" <enum name=\"NEEDS ACTION\" value=\"1\"/>\n"
-" <enum mode=\"defaultvalue\" value=\"1\"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->\n"
-" <enum name=\"ACCEPTED\" value=\"4\"/>\n"
-" <enum name=\"DECLINED\" value=\"7\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"5\"/>\n"
-" <enum name=\"DELEGATED\" value=\"6\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"ATTENDEE\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"ATTENDEES\" conversion=\"mailto\"/>\n"
-" <position field=\"ATTENDEES\" repeat=\"array\" increment=\"1\" minshow=\"0\"/>\n"
-" <parameter name=\"CN\" default=\"no\" show=\"yes\" shownonempty=\"yes\">\n"
-" <value field=\"ATTENDEE_CNS\"/>\n"
-" </parameter>\n"
-" <parameter name=\"PARTSTAT\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ATTENDEE_PARTSTATS\">\n"
-" <enum name=\"NEEDS-ACTION\" value=\"1\"/>\n"
-" <enum mode=\"defaultvalue\" value=\"1\"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->\n"
-" <enum name=\"ACCEPTED\" value=\"4\"/>\n"
-" <enum name=\"DECLINED\" value=\"7\"/>\n"
-" <enum name=\"TENTATIVE\" value=\"5\"/>\n"
-" <enum name=\"DELEGATED\" value=\"6\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" <parameter name=\"ROLE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ATTENDEE_ROLE\">\n"
-" <enum name=\"CHAIR\" value=\"1\"/>\n"
-" <enum name=\"REQ-PARTICIPANT\" value=\"2\"/>\n"
-" <enum name=\"OPT-PARTICIPANT\" value=\"3\"/>\n"
-" <enum name=\"NON-PARTICIPANT\" value=\"4\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" <parameter name=\"RSVP\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ATTENDEE_RSVP\">\n"
-" <enum name=\"TRUE\" value=\"1\"/>\n"
-" <enum name=\"FALSE\" value=\"0\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" <parameter name=\"LANGUAGE\" show=\"yes\">\n"
-" <value field=\"ATTENDEE_LANG\"/>\n"
-" </parameter>\n"
-" <parameter name=\"CUTYPE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ATTENDEE_CUTYPE\">\n"
-" <enum name=\"INDIVIDUAL\" value=\"1\"/>\n"
-" <enum name=\"GROUP\" value=\"2\"/>\n"
-" <enum name=\"RESOURCE\" value=\"3\"/>\n"
-" <enum name=\"ROOM\" value=\"4\"/>\n"
-" <enum name=\"UNKNOWN\" value=\"5\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-" <property name=\"ORGANIZER\" suppressempty=\"yes\" onlyformode=\"standard\">\n"
-" <value field=\"ORGANIZER\" conversion=\"mailto\"/>\n"
-" <parameter name=\"CN\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ORGANIZER_CN\"/>\n"
-" </parameter>\n"
-" </property>\n"
-"\n"
-"\n"
-" <!-- AALARM and DALARM both use the same fields -->\n"
-" <property name=\"AALARM\" onlyformode=\"old\" values=\"4\" suppressempty=\"yes\">\n"
-" <value index=\"0\" field=\"ALARM_TIME\" conversion=\"emptyonly\"/>\n"
-" <value index=\"1\" field=\"ALARM_SNOOZE\" conversion=\"emptyonly\"/>\n"
-" <value index=\"2\" field=\"ALARM_REPEAT\" conversion=\"emptyonly\"/>\n"
-" <value index=\"3\" field=\"ALARM_MSG\" conversion=\"emptyonly\"/>\n"
-" </property>\n"
-" <property name=\"DALARM\" onlyformode=\"old\" values=\"4\" suppressempty=\"yes\">\n"
-" <value index=\"0\" field=\"ALARM_TIME\" conversion=\"emptyonly\"/>\n"
-" <value index=\"1\" field=\"ALARM_SNOOZE\" conversion=\"emptyonly\"/>\n"
-" <value index=\"2\" field=\"ALARM_REPEAT\" conversion=\"emptyonly\"/>\n"
-" <value index=\"3\" field=\"ALARM_MSG\" conversion=\"emptyonly\"/>\n"
-" </property>\n"
-"\n"
-" <subprofile onlyformode=\"standard\" name=\"VALARM\" nummandatory=\"1\" field=\"ALARM_TIME\">\n"
-" <property name=\"TRIGGER\" suppressempty=\"no\" mandatory=\"yes\">\n"
-" <value field=\"ALARM_TIME\"/>\n"
-" <parameter name=\"VALUE\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ALARM_TIME\" conversion=\"FULLVALUETYPE\"/>\n"
-" </parameter>\n"
-" <parameter name=\"RELATED\" default=\"no\" show=\"yes\">\n"
-" <value field=\"ALARM_REL\">\n"
-" <enum mode=\"ignore\" value=\"0\"/>\n"
-" <enum name=\"START\" value=\"1\"/>\n"
-" <enum name=\"END\" value=\"2\"/>\n"
-" </value>\n"
-" </parameter>\n"
-" </property>\n"
-" <property name=\"ACTION\" suppressempty=\"yes\" mandatory=\"yes\">\n"
-" <value field=\"ALARM_ACTION\"/>\n"
-" </property>\n"
-" <property name=\"DESCRIPTION\" suppressempty=\"yes\">\n"
-" <value field=\"ALARM_MSG\"/>\n"
-" </property>\n"
-" <property name=\"REPEAT\" suppressempty=\"yes\">\n"
-" <value field=\"ALARM_REPEAT\"/>\n"
-" </property>\n"
-" <property name=\"X-EVOLUTION-ALARM-UID\" suppressempty=\"yes\">\n"
-" <value field=\"ALARM_UID\"/>\n"
-" </property>\n"
-" </subprofile>\n"
-"\n"
-" </subprofile>\n"
-" \n"
-" </profile>\n"
-" </mimeprofile>\n"
-"\n"
-"\n"
-" <!-- vCalendar 1.0 datatype, using vCalendar profile defined above -->\n"
-" <datatype name=\"vCalendar10\" basetype=\"vcalendar\">\n"
-" <version>1.0</version>\n"
-" <use mimeprofile=\"vCalendar\"/>\n"
-"\n"
-" <incomingscript><![CDATA[\n"
-" $VCALENDAR_INCOMING_SCRIPT\n"
-" ]]></incomingscript>\n"
-" \n"
-" <outgoingscript><![CDATA[\n"
-" $VCALENDAR_OUTGOING_SCRIPT\n"
-" ]]></outgoingscript>\n"
-"\n"
-" </datatype>\n"
-"\n"
-"\n"
-" <!-- iCalendar 2.0 datatype, using vCalendar profile defined above -->\n"
-" <datatype name=\"iCalendar20\" basetype=\"vcalendar\">\n"
-" <version>2.0</version>\n"
-" <use mimeprofile=\"vCalendar\"/>\n"
-"\n"
-" <incomingscript><![CDATA[\n"
-" $VCALENDAR_INCOMING_SCRIPT\n"
-" ]]></incomingscript>\n"
-"\n"
-"\n"
-" <outgoingscript><![CDATA[\n"
-" $VCALENDAR_OUTGOING_SCRIPT\n"
-" ]]></outgoingscript>\n"
-"\n"
-" </datatype>\n"
-"\n"
-"\n"
-" <!-- list of internal fields representing plain text note data -->\n"
-" <fieldlist name=\"Note\">\n"
-" <field name=\"SYNCLVL\" type=\"integer\" compare=\"never\"/>\n"
-" <field name=\"SUBJECT\" type=\"multiline\" compare=\"always\"/>\n"
-" <field name=\"TEXT\" type=\"multiline\" compare=\"conflict\" merge=\"lines\"/>\n"
-" </fieldlist>\n"
-"\n"
-" <textprofile name=\"Note\" fieldlist=\"Note\">\n"
-" <linemap field=\"SUBJECT\">\n"
-" <numlines>1</numlines>\n"
-" <inheader>false</inheader>\n"
-" <allowempty>true</allowempty>\n"
-" <filterkeyword>SUBJECT</filterkeyword>\n"
-" </linemap>\n"
-" <linemap field=\"TEXT\">\n"
-" <numlines>0</numlines>\n"
-" <inheader>false</inheader>\n"
-" <allowempty>true</allowempty>\n"
-" </linemap>\n"
-" </textprofile>\n"
-"\n"
-" <datatype name=\"note10\" basetype=\"text\">\n"
-" <use profile=\"Note\"/>\n"
-" <typestring>text/plain</typestring>\n"
-" <versionstring>1.0</versionstring>\n"
-" </datatype>\n"
-"\n"
-" <datatype name=\"note11\" basetype=\"text\">\n"
-" <use profile=\"Note\"/>\n"
-" <typestring>text/plain</typestring>\n"
-" <versionstring>1.1</versionstring>\n"
-" </datatype>\n"
-"\n"
-"\n"
-" <!-- list of internal fields representing vBookmark data -->\n"
-" <fieldlist name=\"bookmarks\">\n"
-" <field name=\"REV\" type=\"timestamp\" compare=\"never\" age=\"yes\"/>\n"
-" <field name=\"SYNCLVL\" type=\"integer\" compare=\"never\"/>\n"
-"\n"
-" <!-- Name -->\n"
-" <field name=\"TITLE\" type=\"string\" compare=\"always\"/>\n"
-"\n"
-" <!-- categories and classification -->\n"
-" <field name=\"CATEGORIES\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-" <field name=\"CLASS\" type=\"string\" compare=\"conflict\" merge=\"fillempty\"/>\n"
-"\n"
-" <!-- web addresses -->\n"
-" <field name=\"URL\" type=\"url\" compare=\"slowsync\" merge=\"fillempty\"/>\n"
-"\n"
-" <!-- Note -->\n"
-" <field name=\"NOTE\" type=\"multiline\" compare=\"conflict\" merge=\"lines\"/>\n"
-"\n"
-" </fieldlist>\n"
-"\n"
-" <!-- vBookmark profile -->\n"
-" <mimeprofile name=\"vBookmark\" fieldlist=\"bookmarks\">\n"
-"\n"
-" <profile name=\"VBKM\" nummandatory=\"0\">\n"
-" <property name=\"VERSION\">\n"
-" <value conversion=\"version\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"X-LAST-MODIFIED\">\n"
-" <value field=\"REV\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"TITLE\">\n"
-" <value field=\"TITLE\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"URL\">\n"
-" <value field=\"URL\"/>\n"
-" </property>\n"
-"\n"
-" <!-- non-standard properties -->\n"
-"\n"
-" <property name=\"CATEGORIES\">\n"
-" <value field=\"CATEGORIES\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"CLASS\" suppressempty=\"yes\">\n"
-" <value field=\"CLASS\"/>\n"
-" </property>\n"
-"\n"
-" <property name=\"NOTE\" filter=\"no\">\n"
-" <value field=\"NOTE\"/>\n"
-" </property>\n"
-"\n"
-" </profile>\n"
-" </mimeprofile>\n"
-"\n"
-" <!-- vBookmark datatype, using vBookmark profile defined above -->\n"
-" <datatype name=\"vBookmark10\" basetype=\"mimedir\">\n"
-" <typestring>text/x-vbookmark</typestring>\n"
-" <versionstring>1.0</versionstring>\n"
-" <use profile=\"vBookmark\"/>\n"
-" </datatype>\n"
-"\n"
-" <fieldlists/>\n"
-" <profiles/>\n"
-" <datatypes/>\n"
-" </datatypes>\n"
-"\n"
-" <clientorserver/>\n"
-"\n"
-" <client type=\"plugin\">\n"
-" <remoterule name=\"ZYB\">\n"
-" <manufacturer>ZYB</manufacturer>\n"
-" <model>ZYB</model>\n"
-" <!-- information to disable anchors checking -->\n"
-" <lenientmode>yes</lenientmode>\n"
-" </remoterule>\n"
-" </client>\n"
-"\n"
-"</sysync_config>\n"
-;
result = tokens.size() > 2 ? StringToResult(tokens[2]) : ITEM_RESULT_MAX;
}
+bool SyncSourceReport::wasChanged(ItemLocation location)
+{
+ for (int i = ITEM_ADDED; i < ITEM_ANY; i++) {
+ if (getItemStat(location, (ItemState)i, ITEM_TOTAL) > 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
std::ostream &operator << (std::ostream &out, const SyncReport &report)
{
report.prettyPrint(out, 0);
}
std::string SyncReport::slowSyncExplanation(const std::string &peer,
- const std::list<std::string> &sources)
+ const std::set<std::string> &sources)
{
if (sources.empty()) {
return "";
std::string SyncReport::slowSyncExplanation(const std::string &peer) const
{
- std::list<std::string> sources;
+ std::set<std::string> sources;
BOOST_FOREACH(const SyncReport::value_type &entry, *this) {
const std::string &name = entry.first;
const SyncSourceReport &source = entry.second;
if (source.getStatus() == STATUS_UNEXPECTED_SLOW_SYNC) {
- sources.push_back(name);
+ string virtualsource = source.getVirtualSource();
+ sources.insert(virtualsource.empty() ?
+ name :
+ virtualsource);
}
}
return slowSyncExplanation(peer, sources);
node.setProperty(key, source.isResumeSync());
key = prefix + "-status";
node.setProperty(key, static_cast<long>(source.getStatus()));
+ string virtualsource = source.getVirtualSource();
+ if (!virtualsource.empty()) {
+ key = prefix + "-virtualsource";
+ node.setProperty(key, virtualsource);
+ }
key = prefix + "-backup-before";
node.setProperty(key, source.m_backupBefore.getNumItems());
key = prefix + "-backup-after";
if (node.getProperty(prop.first, value)) {
source.recordStatus(static_cast<SyncMLStatus>(value));
}
+ } else if (key == "virtualsource") {
+ source.recordVirtualSource(node.readProperty(prop.first));
} else if (key == "backup-before") {
long value;
if (node.getProperty(prop.first, value)) {
#include <string>
#include <map>
#include <list>
+#include <set>
#include <ostream>
#include <string.h>
/** no error at the SyncML level, but some items did not transfer correctly */
STATUS_PARTIAL_FAILURE = 22001,
+ /**
+ * Set by SyncEvolution in status.ini before starting an sync.
+ * Replaced with the final status code if the sync completes.
+ * Finding this code here in a session report implies that
+ * the process responsible for the session died unexpectedly,
+ * for unknown reasons.
+ */
+ STATUS_DIED_PREMATURELY = 22002,
+
STATUS_MAX = 0x7FFFFFF
};
m_stat[location][state][success]++;
}
+ /** true if statistics indicate that peer or local was modified during sync */
+ bool wasChanged(ItemLocation location);
+
void recordFinalSyncMode(SyncMode mode) { m_mode = mode; }
SyncMode getFinalSyncMode() const { return m_mode; }
void recordStatus(SyncMLStatus status ) { m_status = status; }
SyncMLStatus getStatus() const { return m_status; }
+ /**
+ * if not empty, then this was the virtual source which cause the
+ * current one to be included in the sync
+ */
+ void recordVirtualSource(const std::string &virtualsource) { m_virtualSource = virtualsource; }
+ std::string getVirtualSource() const { return m_virtualSource; }
+
/** information about database dump before and after session */
BackupReport m_backupBefore, m_backupAfter;
bool m_first;
bool m_resume;
SyncMLStatus m_status;
+ std::string m_virtualSource;
};
class SyncReport : public std::map<std::string, SyncSourceReport> {
m_status(STATUS_OK)
{}
+ typedef std::pair<std::string, SyncSourceReport> SourceReport_t;
+
void addSyncSourceReport(const std::string &name,
const SyncSourceReport &report) {
(*this)[name] = report;
* @return explanation, empty string if list of sources is empty
*/
static std::string slowSyncExplanation(const std::string &peer,
- const std::list<std::string> &sources);
+ const std::set<std::string> &sources);
/**
* Produces a non-localized explanation for recovering from unexpected
return scannedModules.debug.str();
}
-SyncSource *SyncSource::createSource(const SyncSourceParams ¶ms, bool error)
+SyncSource *SyncSource::createSource(const SyncSourceParams ¶ms, bool error, SyncConfig *config)
{
string sourceTypeString = getSourceTypeString(params.m_nodes);
SourceType sourceType = getSourceType(params.m_nodes);
+ if (sourceType.m_backend == "virtual") {
+ SyncSource *source = NULL;
+ source = new VirtualSyncSource(params, config);
+ if (error && !source) {
+ SyncContext::throwError(params.m_name + ": virtual source cannot be instantiated");
+ }
+ return source;
+ }
+
const SourceRegistry ®istry(getSourceRegistry());
BOOST_FOREACH(const RegisterSyncSource *sourceInfos, registry) {
SyncSource *source = sourceInfos->m_create(params);
return createSource(params, error);
}
+VirtualSyncSource::VirtualSyncSource(const SyncSourceParams ¶ms, SyncConfig *config) :
+ DummySyncSource(params)
+{
+ if (config) {
+ BOOST_FOREACH(std::string name, getMappedSources()) {
+ SyncSourceNodes source = config->getSyncSourceNodes(name);
+ SyncSourceParams params(name, source);
+ boost::shared_ptr<SyncSource> syncSource(createSource(params, true, config));
+ m_sources.push_back(syncSource);
+ }
+ }
+}
+
+void VirtualSyncSource::open()
+{
+ getDataTypeSupport();
+ BOOST_FOREACH(boost::shared_ptr<SyncSource> &source, m_sources) {
+ source->open();
+ }
+}
+
+void VirtualSyncSource::close()
+{
+ BOOST_FOREACH(boost::shared_ptr<SyncSource> &source, m_sources) {
+ source->close();
+ }
+}
+
+std::vector<std::string> VirtualSyncSource::getMappedSources()
+{
+ std::string evoSyncSource = getDatabaseID();
+ std::vector<std::string> mappedSources = unescapeJoinedString (evoSyncSource, ',');
+ return mappedSources;
+}
+
+std::string VirtualSyncSource::getDataTypeSupport()
+{
+ string datatypes;
+ SourceType sourceType = getSourceType();
+ string type = sourceType.m_format;
+
+ datatypes = getDataTypeSupport(type, sourceType.m_forceFormat);
+ return datatypes;
+}
+
void SyncSourceSession::init(SyncSource::Operations &ops)
{
ops.m_startDataRead = boost::bind(&SyncSourceSession::startDataRead, this, _1, _2);
if (!sourceType.m_format.empty()) {
type = sourceType.m_format;
}
+ info.m_datatypes = getDataTypeSupport(type, sourceType.m_forceFormat);
+}
+
+std::string SyncSourceBase::getDataTypeSupport(const std::string &type,
+ bool forceFormat)
+{
+ std::string datatypes;
if (type == "text/x-vcard:2.1" || type == "text/x-vcard") {
- info.m_datatypes =
+ datatypes =
" <use datatype='vCard21' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- info.m_datatypes +=
+ if (!forceFormat) {
+ datatypes +=
" <use datatype='vCard30' mode='rw'/>\n";
}
} else if (type == "text/vcard:3.0" || type == "text/vcard") {
- info.m_datatypes =
+ datatypes =
" <use datatype='vCard30' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- info.m_datatypes +=
+ if (!forceFormat) {
+ datatypes +=
" <use datatype='vCard21' mode='rw'/>\n";
}
} else if (type == "text/x-vcalendar:1.0" || type == "text/x-vcalendar"
|| type == "text/x-calendar:1.0" || type == "text/x-calendar") {
- info.m_datatypes =
+ datatypes =
" <use datatype='vcalendar10' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- info.m_datatypes +=
+ if (!forceFormat) {
+ datatypes +=
" <use datatype='icalendar20' mode='rw'/>\n";
}
} else if (type == "text/calendar:2.0" || type == "text/calendar") {
- info.m_datatypes =
+ datatypes =
" <use datatype='icalendar20' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- info.m_datatypes +=
+ if (!forceFormat) {
+ datatypes +=
" <use datatype='vcalendar10' mode='rw'/>\n";
}
} else if (type == "text/plain:1.0" || type == "text/plain") {
// note10 are the same as note11, so ignore force format
- info.m_datatypes =
+ datatypes =
" <use datatype='note10' mode='rw' preferred='yes'/>\n"
" <use datatype='note11' mode='rw'/>\n";
+ } else if (type.empty()) {
+ throwError("no MIME type configured");
} else {
throwError(string("configured MIME type not supported: ") + type);
}
+
+ return datatypes;
}
sysync::TSyError SyncSourceSerialize::readItemAsKey(sysync::cItemID aID, sysync::KeyH aItemKey)
this, _1, _2, _3);
}
+/**
+ * Mapping from Hash() value to file.
+ */
+class ItemCache
+{
+public:
+#ifdef USE_SHA256
+ typedef std::string Hash_t;
+ Hash_t hashFunc(const std::string &data) { return SHA_256(data); }
+#else
+ typedef unsigned long Hash_t;
+ Hash_t hashFunc(const std::string &data) { return Hash(data); }
+#endif
+ typedef unsigned long Counter_t;
+
+ /** mark the algorithm used for the hash via different suffices */
+ static const char *m_hashSuffix;
+
+ /**
+ * Collect information about stored hashes. Provides
+ * access to file name via hash.
+ *
+ * If no hashes were written (as in an old SyncEvoltion
+ * version), we could read the files to recreate the
+ * hashes. This is not done because it won't occur
+ * often enough.
+ *
+ * Hashes are also not verified. Users should better
+ * not edit them or file contents...
+ *
+ * @param oldBackup existing backup to read; may be empty
+ */
+ void init(const SyncSource::Operations::ConstBackupInfo &oldBackup)
+ {
+ m_hash2counter.clear();
+ m_dirname = oldBackup.m_dirname;
+ if (m_dirname.empty() || !oldBackup.m_node) {
+ return;
+ }
+
+ long numitems;
+ if (!oldBackup.m_node->getProperty("numitems", numitems)) {
+ return;
+ }
+ for (long counter = 1; counter <= numitems; counter++) {
+ stringstream key;
+ key << counter << m_hashSuffix;
+ Hash_t hash;
+ if (oldBackup.m_node->getProperty(key.str(), hash)) {
+ m_hash2counter[hash] = counter;
+ }
+ }
+ }
+
+ /**
+ * create file name for a specific hash, empty if no such hash
+ */
+ string getFilename(Hash_t hash)
+ {
+ Map_t::const_iterator it = m_hash2counter.find(hash);
+ if (it != m_hash2counter.end()) {
+ stringstream dirname;
+ dirname << m_dirname << "/" << it->second;
+ return dirname.str();
+ } else {
+ return "";
+ }
+ }
+
+private:
+ typedef std::map<Hash_t, Counter_t> Map_t;
+ Map_t m_hash2counter;
+ string m_dirname;
+};
+
+const char *ItemCache::m_hashSuffix =
+#ifdef USE_SHA256
+ "-sha256"
+#else
+ "-hash"
+#endif
+;
-void SyncSourceRevisions::backupData(const string &dir, ConfigNode &node, BackupReport &report)
+void SyncSourceRevisions::initRevisions()
{
- RevisionMap_t revisions;
- listAllItems(revisions);
+ if (!m_revisionsSet) {
+ listAllItems(m_revisions);
+ m_revisionsSet = true;
+ }
+}
+
+
+void SyncSourceRevisions::backupData(const SyncSource::Operations::ConstBackupInfo &oldBackup,
+ const SyncSource::Operations::BackupInfo &newBackup,
+ BackupReport &report)
+{
+ ItemCache cache;
+ cache.init(oldBackup);
+
+ bool startOfSync = newBackup.m_mode == SyncSource::Operations::BackupInfo::BACKUP_BEFORE;
+ RevisionMap_t buffer;
+ RevisionMap_t *revisions;
+ if (startOfSync) {
+ initRevisions();
+ revisions = &m_revisions;
+ } else {
+ listAllItems(buffer);
+ revisions = &buffer;
+ }
unsigned long counter = 1;
string item;
errno = 0;
- BOOST_FOREACH(const StringPair &mapping, revisions) {
+ BOOST_FOREACH(const StringPair &mapping, *revisions) {
const string &uid = mapping.first;
const string &rev = mapping.second;
m_raw->readItemRaw(uid, item);
stringstream filename;
- filename << dir << "/" << counter;
+ filename << newBackup.m_dirname << "/" << counter;
+
+ ItemCache::Hash_t hash = cache.hashFunc(item);
+ string oldfilename = cache.getFilename(hash);
+ if (!oldfilename.empty()) {
+ // found old file with same content, reuse it via hardlink
+ if (link(oldfilename.c_str(), filename.str().c_str())) {
+ // Hard linking failed. Record this, then continue
+ // by ignoring the old file.
+ SE_LOG_DEBUG(NULL, NULL, "hard linking old %s new %s: %s",
+ oldfilename.c_str(),
+ filename.str().c_str(),
+ strerror(errno));
+ oldfilename.clear();
+ }
+ }
- ofstream out(filename.str().c_str());
- out.write(item.c_str(), item.size());
- out.close();
- if (out.fail()) {
- throwError(string("error writing ") + filename.str() + ": " + strerror(errno));
+ if (oldfilename.empty()) {
+ // write new file instead of reusing old one
+ ofstream out(filename.str().c_str());
+ out.write(item.c_str(), item.size());
+ out.close();
+ if (out.fail()) {
+ throwError(string("error writing ") + filename.str() + ": " + strerror(errno));
+ }
}
stringstream key;
key << counter << "-uid";
- node.setProperty(key.str(), uid);
+ newBackup.m_node->setProperty(key.str(), uid);
+ // clear() does not remove the existing content, which was
+ // intended here. This should have been key.str(""). As a
+ // result, keys for -rev are longer than intended because they
+ // start with the -uid part. We cannot change it now, because
+ // that would break compatibility with nodes that use the
+ // older, longer keys for -rev.
key.clear();
key << counter << "-rev";
- node.setProperty(key.str(), rev);
+ newBackup.m_node->setProperty(key.str(), rev);
+ key.str("");
+ key << counter << ItemCache::m_hashSuffix;
+ newBackup.m_node->setProperty(key.str(), hash);
counter++;
}
stringstream value;
value << counter - 1;
- node.setProperty("numitems", value.str());
- node.flush();
+ newBackup.m_node->setProperty("numitems", value.str());
+ newBackup.m_node->flush();
report.setNumItems(counter - 1);
}
-void SyncSourceRevisions::restoreData(const string &dir, const ConfigNode &node, bool dryrun, SyncSourceReport &report)
+void SyncSourceRevisions::restoreData(const SyncSource::Operations::ConstBackupInfo &oldBackup,
+ bool dryrun,
+ SyncSourceReport &report)
{
RevisionMap_t revisions;
listAllItems(revisions);
long numitems;
string strval;
- strval = node.readProperty("numitems");
+ strval = oldBackup.m_node->readProperty("numitems");
stringstream stream(strval);
stream >> numitems;
for (long counter = 1; counter <= numitems; counter++) {
stringstream key;
key << counter << "-uid";
- string uid = node.readProperty(key.str());
+ string uid = oldBackup.m_node->readProperty(key.str());
key.clear();
key << counter << "-rev";
- string rev = node.readProperty(key.str());
+ string rev = oldBackup.m_node->readProperty(key.str());
RevisionMap_t::iterator it = revisions.find(uid);
report.incrementItemStat(report.ITEM_LOCAL,
report.ITEM_ANY,
} else {
// add or update, so need item
stringstream filename;
- filename << dir << "/" << counter;
+ filename << oldBackup.m_dirname << "/" << counter;
string data;
if (!ReadFile(filename.str(), data)) {
throwError(StringPrintf("restoring %s from %s failed: could not read file",
void SyncSourceRevisions::detectChanges(ConfigNode &trackingNode)
{
- RevisionMap_t revisions;
- listAllItems(revisions);
+ initRevisions();
- BOOST_FOREACH(const StringPair &mapping, revisions) {
+ BOOST_FOREACH(const StringPair &mapping, m_revisions) {
const string &uid = mapping.first;
const string &revision = mapping.second;
m_del = del;
m_modTimeStamp = 0;
m_revisionAccuracySeconds = granularity;
+ m_revisionsSet = false;
if (raw) {
ops.m_backupData = boost::bind(&SyncSourceRevisions::backupData,
this, _1, _2, _3);
}
if (raw && del) {
ops.m_restoreData = boost::bind(&SyncSourceRevisions::restoreData,
- this, _1, _2, _3, _4);
+ this, _1, _2, _3);
}
ops.m_endSession.push_back(boost::bind(&SyncSourceRevisions::sleepSinceModification,
this));
*/
virtual void getSynthesisInfo(SynthesisInfo &info,
XMLConfigFragments &fragments) = 0;
+
+ /**
+ * utility code: creates Synthesis <use datatype=...>
+ * statements, using the predefined vCard21/vCard30/vcalendar10/icalendar20
+ * types. Throws an error if no suitable result can be returned (empty or invalid type)
+ *
+ * @param type the format specifier as used in SyncEvolution configs, with and without version
+ * (text/x-vcard:2.1, text/x-vcard, text/x-vcalendar, text/calendar, text/plain, ...);
+ * see SourceType::m_format
+ * @param forceFormat if true, then don't allow alternative formats (like vCard 3.0 in addition to 2.1);
+ * see SourceType::m_force
+ * @return generated XML fragment
+ */
+ std::string getDataTypeSupport(const std::string &type,
+ bool forceFormat);
};
/**
public:
SyncSource(const SyncSourceParams ¶ms) :
SyncSourceConfig(params.m_name, params.m_nodes),
- m_numDeleted(0)
+ m_numDeleted(0),
+ m_forceSlowSync(false)
{
}
virtual ~SyncSource() {}
/**
* Actually opens the data source specified in the constructor,
* will throw the normal exceptions if that fails. Should
- * not modify the state of the sync source: that can be deferred
- * until the server is also ready and beginSync() is called.
+ * not modify the state of the sync source.
+ *
+ * The expectation is that this call is fairly light-weight, but
+ * does enough checking to determine whether the source is
+ * usable. More expensive operations (like determining changes)
+ * should be done in the m_startDataRead callback (bound to
+ * beginSync() in some of the utility classes).
+ *
+ * In clients, it will be called for all sources before
+ * the sync starts. In servers, it is called for each source once
+ * the client asks for it, but not sooner.
*/
virtual void open() = 0;
*/
struct Operations {
/**
- * Dump all data from source unmodified into the given directory.
- * The ConfigNode can be used to store meta information needed for
- * restoring that state. Both directory and node are empty.
+ * The caller determines where item data is stored (m_dirname)
+ * and where meta information about them (m_node). The callee
+ * then can use both arbitrarily. As an additional hint,
+ * m_mode specifies why and when the backup is made, which
+ * is useful to determine whether information can be reused.
+ */
+ struct BackupInfo {
+ enum Mode {
+ BACKUP_BEFORE, /**< directly at start of sync */
+ BACKUP_AFTER, /**< directly after sync */
+ BACKUP_OTHER
+ } m_mode;
+ string m_dirname;
+ boost::shared_ptr<ConfigNode> m_node;
+ BackupInfo() {}
+ BackupInfo(Mode mode,
+ const string &dirname,
+ const boost::shared_ptr<ConfigNode> &node) :
+ m_mode(mode),
+ m_dirname(dirname),
+ m_node(node)
+ {}
+ };
+ struct ConstBackupInfo {
+ BackupInfo::Mode m_mode;
+ string m_dirname;
+ boost::shared_ptr<const ConfigNode> m_node;
+ ConstBackupInfo() {}
+ ConstBackupInfo(BackupInfo::Mode mode,
+ const string &dirname,
+ const boost::shared_ptr<const ConfigNode> &node) :
+ m_mode(mode),
+ m_dirname(dirname),
+ m_node(node)
+ {}
+ };
+
+ /**
+ * Dump all data from source unmodified into the given backup location.
* Information about the created backup is added to the
* report.
*
- * Required for the backup/restore functionality in SyncEvolution,
- * not for syncing itself.
+ * Required for the backup/restore functionality in
+ * SyncEvolution, not for syncing itself. But typically it is
+ * called before syncing (can be turned off by users), so
+ * implementations can reuse the information gathered while
+ * making a backup in later operations.
+ *
+ * @param previous the most recent backup, empty m_dirname if none
+ * @param next the backup which is to be created, directory and node are empty
+ * @param report to be filled with information about backup (number of items, etc.)
*/
- typedef void (BackupData_t)(const string &dirname, ConfigNode &node, BackupReport &report);
+ typedef void (BackupData_t)(const ConstBackupInfo &oldBackup,
+ const BackupInfo &newBackup,
+ BackupReport &report);
boost::function<BackupData_t> m_backupData;
/**
* Restore database from data stored in backupData().
+ * If possible don't touch items which are the same as in the
+ * backup, to mimimize impact on future incremental syncs.
+ *
+ * @param oldBackup the backup which is to be restored
+ * @param dryrun pretend to restore and fill in report, without
+ * actually touching backend data
+ * @param report to be filled with information about restore
+ * (number of total items and changes)
*/
- typedef void (RestoreData_t)(const string &dirname, const ConfigNode &node, bool dryrun, SyncSourceReport &report);
+ typedef void (RestoreData_t)(const ConstBackupInfo &oldBackup,
+ bool dryrun,
+ SyncSourceReport &report);
boost::function<RestoreData_t> m_restoreData;
/**
boost::function<CheckStatus_t> m_checkStatus;
/**
+ * A quick check whether the source currently has data.
+ *
+ * If this cannot be determined easily, don't provide the
+ * operation. The information is currently only used to
+ * determine whether a slow sync should be allowed. If
+ * the operation is not provided, the assumption is that
+ * there is local data, which disables the "allow slow
+ * sync for empty databases" heuristic and forces the user
+ * to choose.
+ */
+ typedef bool (IsEmpty_t)();
+ boost::function<IsEmpty_t> m_isEmpty;
+
+ /**
* Synthesis DB API callbacks. For documentation see the
* Synthesis API specification (PDF and/or sync_dbapi.h).
*
* to be part of a sync session.
*/
/**@{*/
+ typedef void (Callback_t)();
+ typedef boost::function<Callback_t> CallbackFunctor_t;
+ typedef std::list<CallbackFunctor_t> Callbacks_t;
+
+ /** all of these functions will be called before accessing
+ the source's data for the first time, i.e., before m_startDataRead */
+ Callbacks_t m_startAccess;
+
typedef sysync::TSyError (StartDataRead_t)(const char *lastToken, const char *resumeToken);
boost::function<StartDataRead_t> m_startDataRead;
- typedef void (Callback_t)();
- typedef boost::function<Callback_t> CallbackFunctor_t;
/** all of these functions will be called directly after
m_startDataRead() returned successfully */
- std::list<CallbackFunctor_t> m_startSession;
+ Callbacks_t m_startSession;
typedef sysync::TSyError (EndDataRead_t)();
boost::function<EndDataRead_t> m_endDataRead;
/**@}*/
};
const Operations &getOperations() { return m_operations; }
+
+ /**
+ * outside users of the source are only allowed to add callbacks,
+ * not overwrite arbitrary operations
+ */
+ void addCallback(Operations::CallbackFunctor_t callback, Operations::Callbacks_t Operations::* where) { (m_operations.*where).push_back(callback); }
/**
* closes the data source so that it can be reopened
* source type specified in the params.m_nodes.m_configNode
*
* @param error throw a runtime error describing what the problem is if no matching source is found
- * @return NULL if no source can handle the given type
+ * @param config optional, needed for intantiating virtual sources
+ * @return valid instance, NULL if no source can handle the given type (only when error==false)
*/
static SyncSource *createSource(const SyncSourceParams ¶ms,
- bool error = true);
+ bool error = true,
+ SyncConfig *config = NULL);
/**
* Factory function for a SyncSource with the given name
virtual void setNumDeleted(long num) { m_numDeleted = num; }
virtual void incrementNumDeleted() { m_numDeleted++; }
+ /**
+ * Set to true in SyncContext::initSAN() when a SyncML server has
+ * to force a client into slow sync mode. This is necessary because
+ * the server cannot request that mode (missing in the standard).
+ * Forcing the slow sync mode is done via a FORCESLOWSYNC() macro
+ * call in an <alertscript>.
+ */
+ void setForceSlowSync(bool forceSlowSync) { m_forceSlowSync = forceSlowSync; }
+ bool getForceSlowSync() const { return m_forceSlowSync; }
+
protected:
Operations m_operations;
*/
long m_numDeleted;
+ bool m_forceSlowSync;
+
/**
* Interface pointer for this sync source, allocated for us by the
* Synthesis engine and registered here by
};
/**
- * Virtual SyncSources
+ * A special source which combines one or more real sources.
+ * Most of the special handling for that is in SyncContext.cpp.
+ *
+ * This class can be instantiated, opened and closed if and only if
+ * the underlying sources also support that.
*/
class VirtualSyncSource : public DummySyncSource
{
+ std::vector< boost::shared_ptr<SyncSource> > m_sources;
+
public:
- VirtualSyncSource(const SyncSourceParams ¶ms) :
- DummySyncSource(params) {}
-
- std::string getDataTypeSupport() {
- string datatypes;
- SourceType sourceType = getSourceType();
- string type = sourceType.m_format;
-
- if (type.empty()) {
- return "";
- } else if (type == "text/x-vcard:2.1" || type == "text/x-vcard") {
- datatypes =
- " <use datatype='vCard21' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- datatypes +=
- " <use datatype='vCard30' mode='rw'/>\n";
- }
- } else if (type == "text/vcard:3.0" || type == "text/vcard") {
- datatypes =
- " <use datatype='vCard30' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- datatypes +=
- " <use datatype='vCard21' mode='rw'/>\n";
- }
- } else if (type == "text/x-vcalendar:1.0" || type == "text/x-vcalendar"
- || type == "text/x-calendar:1.0" || type == "text/x-calendar") {
- datatypes =
- " <use datatype='vcalendar10' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- datatypes +=
- " <use datatype='icalendar20' mode='rw'/>\n";
- }
- } else if (type == "text/calendar:2.0" || type == "text/calendar") {
- datatypes =
- " <use datatype='icalendar20' mode='rw' preferred='yes'/>\n";
- if (!sourceType.m_forceFormat) {
- datatypes +=
- " <use datatype='vcalendar10' mode='rw'/>\n";
- }
- } else if (type == "text/plain:1.0" || type == "text/plain") {
- // note10 are the same as note11, so ignore force format
- datatypes =
- " <use datatype='note10' mode='rw' preferred='yes'/>\n"
- " <use datatype='note11' mode='rw'/>\n";
- } else {
- throwError(string("configured MIME type not supported: ") + type);
- }
- return datatypes;
- }
+ /**
+ * @param config optional: when given, the constructor will instantiate the
+ * referenced underlying sources and check them in open()
+ */
+ VirtualSyncSource(const SyncSourceParams ¶ms, SyncConfig *config = NULL);
+
+ /** opens underlying sources and checks config by calling getDataTypeSupport() */
+ virtual void open();
+ virtual void close();
+
+ /**
+ * returns array with source names that are referenced by this
+ * virtual source
+ */
+ std::vector<std::string> getMappedSources();
+
+ /**
+ * returns <use datatype=...> statements for XML config,
+ * throws error if not configured correctly
+ */
+ std::string getDataTypeSupport();
+ using SyncSourceBase::getDataTypeSupport;
};
/**
* should not throw errors when it cannot create a non-empty
* string. The caller of this method will detect situations where
* a non-empty string is necessary and none was provided.
+ *
+ * This call is typically only invoked only once during the
+ * lifetime of a source. The result returned in that invocation is
+ * used throught the session.
*/
virtual void listAllItems(RevisionMap_t &revisions) = 0;
SyncSourceDelete *m_del;
int m_revisionAccuracySeconds;
+ /** buffers the result of the initial listAllItems() call */
+ RevisionMap_t m_revisions;
+ bool m_revisionsSet;
+ void initRevisions();
+
/**
* Dump all data from source unmodified into the given directory.
* The ConfigNode can be used to store meta information needed for
* restoring that state. Both directory and node are empty.
*/
- void backupData(const string &dirname, ConfigNode &node, BackupReport &report);
+ void backupData(const SyncSource::Operations::ConstBackupInfo &oldBackup,
+ const SyncSource::Operations::BackupInfo &newBackup,
+ BackupReport &report);
/**
* Restore database from data stored in backupData(). Will be
* called inside open()/close() pair. beginSync() is *not* called.
*/
- void restoreData(const string &dirname, const ConfigNode &node, bool dryrun, SyncSourceReport &report);
+ void restoreData(const SyncSource::Operations::ConstBackupInfo &oldBackup,
+ bool dryrun,
+ SyncSourceReport &report);
/**
* Increments the time stamp of the latest database modification,
}
TSyError res = LOCERR_OK;
try {
+ BOOST_FOREACH(const SyncSource::Operations::CallbackFunctor_t &callback,
+ source->getOperations().m_startAccess) {
+ callback();
+ }
if (source->getOperations().m_startDataRead) {
res = source->getOperations().m_startDataRead(lastToken, resumeToken);
}
boost::shared_ptr<ConfigNode>(new SafeConfigNode(params.m_nodes.getTrackingNode()))))
{
m_operations.m_checkStatus = boost::bind(&TrackingSyncSource::checkStatus, this, _1);
+ m_operations.m_isEmpty = boost::bind(&TrackingSyncSource::isEmpty, this);
SyncSourceRevisions::init(this, this, granularitySeconds, m_operations);
}
~TrackingSyncSource() {}
/**
+ * ConfigNode used for change tracking in SyncSourceRevisions.
+ * Derived classes might need that when implementing operations
+ * which have side effects on other items (for example,
+ * EvolutionCalendarSource::removeItem()).
+ */
+ ConfigNode &getTrackingNode() { return *m_trackingNode; }
+
+ /**
* returns a list of all know sources for the kind of items
* supported by this sync source
*/
/**
* Actually opens the data source specified in the constructor,
* will throw the normal exceptions if that fails. Should
- * not modify the state of the sync source: that can be deferred
- * until the server is also ready and beginSync() is called.
+ * not modify the state of the sync source.
+ *
+ * The expectation is that this call is fairly light-weight, but
+ * does enough checking to determine whether the source is
+ * usable. More expensive operations (like determining changes)
+ * should be done in the beginSync() callback.
+ *
+ * In clients, it will be called for all sources before
+ * the sync starts. In servers, it is called for each source once
+ * the client asks for it, but not sooner.
*/
virtual void open() = 0;
/**
+ * A quick check whether the source currently has data. Currently
+ * used as part of the "allow slow sync" checking after open() and
+ * before beginSync(). Returning false is acceptable when it is
+ * uncertain and too expensive to check.
+ */
+ virtual bool isEmpty() = 0;
+
+ /**
* fills the complete mapping from LUID to revision string of all
* currently existing items
*
--- /dev/null
+xmldir = $(datadir)/syncevolution/xml
+nobase_dist_xml_DATA = $(shell cd $(srcdir) && find * -name '*.xml') update-samples.pl
--- /dev/null
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/syncevo/configs
+DIST_COMMON = README $(nobase_dist_xml_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4-repo/ax_boost_base.m4 \
+ $(top_srcdir)/m4/intltool.m4 $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(xmldir)"
+nobase_dist_xmlDATA_INSTALL = $(install_sh_DATA)
+DATA = $(nobase_dist_xml_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADDRESSBOOK_CFLAGS = @ADDRESSBOOK_CFLAGS@
+ADDRESSBOOK_LIBS = @ADDRESSBOOK_LIBS@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BACKEND_CPPFLAGS = @BACKEND_CPPFLAGS@
+BACKEND_DEFINES = @BACKEND_DEFINES@
+BLUEZ_CFLAGS = @BLUEZ_CFLAGS@
+BLUEZ_LIBS = @BLUEZ_LIBS@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDFLAGS = @BOOST_LDFLAGS@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CORE_LDADD_DEP = @CORE_LDADD_DEP@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPUNIT_CXXFLAGS = @CPPUNIT_CXXFLAGS@
+CPPUNIT_LDFLAGS = @CPPUNIT_LDFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_BINDING_TOOL = @DBUS_BINDING_TOOL@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_GLIB_CFLAGS = @DBUS_GLIB_CFLAGS@
+DBUS_GLIB_LIBS = @DBUS_GLIB_LIBS@
+DBUS_LIBS = @DBUS_LIBS@
+DBUS_SERVICES_DIR = @DBUS_SERVICES_DIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+EBOOK_CFLAGS = @EBOOK_CFLAGS@
+EBOOK_LIBS = @EBOOK_LIBS@
+ECAL_CFLAGS = @ECAL_CFLAGS@
+ECAL_LIBS = @ECAL_LIBS@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EPACKAGE_CFLAGS = @EPACKAGE_CFLAGS@
+EPACKAGE_LIBS = @EPACKAGE_LIBS@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FILE_CFLAGS = @FILE_CFLAGS@
+FILE_LIBS = @FILE_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GREP = @GREP@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+GTK_2_18_CFLAGS = @GTK_2_18_CFLAGS@
+GTK_2_18_LIBS = @GTK_2_18_LIBS@
+GTK_BUILDER_CONV = @GTK_BUILDER_CONV@
+GUI_CFLAGS = @GUI_CFLAGS@
+GUI_DESKTOP_FILES = @GUI_DESKTOP_FILES@
+GUI_LIBS = @GUI_LIBS@
+GUI_PROGRAMS = @GUI_PROGRAMS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+KEYRING_2_20_CFLAGS = @KEYRING_2_20_CFLAGS@
+KEYRING_2_20_LIBS = @KEYRING_2_20_LIBS@
+KEYRING_CFLAGS = @KEYRING_CFLAGS@
+KEYRING_LIBS = @KEYRING_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
+LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
+LIBS = @LIBS@
+LIBSOUP_CFLAGS = @LIBSOUP_CFLAGS@
+LIBSOUP_LIBS = @LIBSOUP_LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MCALB_CFLAGS = @MCALB_CFLAGS@
+MCALB_LIBS = @MCALB_LIBS@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MODIFY_SYNCCOMPARE = @MODIFY_SYNCCOMPARE@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CFLAGS = @SQLITE_CFLAGS@
+SQLITE_LIBS = @SQLITE_LIBS@
+STABLE_VERSION = @STABLE_VERSION@
+STRIP = @STRIP@
+SYNCEVOLUTION_CXXFLAGS = @SYNCEVOLUTION_CXXFLAGS@
+SYNCEVOLUTION_LDADD = @SYNCEVOLUTION_LDADD@
+SYNCEVOLUTION_LOCALEDIR = @SYNCEVOLUTION_LOCALEDIR@
+SYNCSOURCES = @SYNCSOURCES@
+SYNTHESIS = @SYNTHESIS@
+SYNTHESISSRC = @SYNTHESISSRC@
+SYNTHESIS_CFLAGS = @SYNTHESIS_CFLAGS@
+SYNTHESIS_DEP = @SYNTHESIS_DEP@
+SYNTHESIS_ENGINE = @SYNTHESIS_ENGINE@
+SYNTHESIS_LIB = @SYNTHESIS_LIB@
+SYNTHESIS_LIBS = @SYNTHESIS_LIBS@
+SYNTHESIS_SRC = @SYNTHESIS_SRC@
+SYNTHESIS_SUBDIR = @SYNTHESIS_SUBDIR@
+TRANSPORT_CFLAGS = @TRANSPORT_CFLAGS@
+TRANSPORT_LIBS = @TRANSPORT_LIBS@
+UNIQUE_CFLAGS = @UNIQUE_CFLAGS@
+UNIQUE_LIBS = @UNIQUE_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XMLRPC_CFLAGS = @XMLRPC_CFLAGS@
+XMLRPC_LIBS = @XMLRPC_LIBS@
+XSLT = @XSLT@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+backenddir = @backenddir@
+backendsearchdir = @backendsearchdir@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+xmldir = $(datadir)/syncevolution/xml
+nobase_dist_xml_DATA = $(shell cd $(srcdir) && find * -name '*.xml') update-samples.pl
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/syncevo/configs/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/syncevo/configs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-nobase_dist_xmlDATA: $(nobase_dist_xml_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(xmldir)" || $(MKDIR_P) "$(DESTDIR)$(xmldir)"
+ @$(am__vpath_adj_setup) \
+ list='$(nobase_dist_xml_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ $(am__vpath_adj) \
+ echo " $(nobase_dist_xmlDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(xmldir)/$$f'"; \
+ $(nobase_dist_xmlDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(xmldir)/$$f"; \
+ done
+
+uninstall-nobase_dist_xmlDATA:
+ @$(NORMAL_UNINSTALL)
+ @$(am__vpath_adj_setup) \
+ list='$(nobase_dist_xml_DATA)'; for p in $$list; do \
+ $(am__vpath_adj) \
+ echo " rm -f '$(DESTDIR)$(xmldir)/$$f'"; \
+ rm -f "$(DESTDIR)$(xmldir)/$$f"; \
+ done
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(xmldir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_dist_xmlDATA
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-nobase_dist_xmlDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man \
+ install-nobase_dist_xmlDATA install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \
+ uninstall-nobase_dist_xmlDATA
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+The sample configs contain common elements (datatypes, scripts, remote
+rules, debug settings) which are maintained as separate files in the
+corresponding directories. When modifying those common elements, run
+"update-samples.pl" in this directory to update the sample configs.
+
+The complete samples are under version control for several reasons:
+1. avoid dependency on Perl unless common elements need to be updated
+2. effect of changes on complete config show up in patches
+3. the file layout and unshared parts (<client> and <server>) are
+ determined by the sample configs
+
+The naming of common elements determines the order in which they get
+inserted. Files not ending in .xml are ignored. Elements that only
+apply to a client or server are stored in the corresponding sub
+directories, while the shared elements are in the
+"debug/scripting/datatypes/remoterules".
+
+It is a somewhat subjective choice which elements are stored in one
+file and which ones are split up. The three elements of a datatype
+definition (field list, profile, datatype) where split up because
+there might be multiple different profiles using the same field list
+and some users of these files might want to replace the default one.
--- /dev/null
+ <!-- list of internal fields representing vCard data -->
+ <fieldlist name="contacts">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="REV" type="timestamp" compare="never" age="yes"/>
+
+ <!-- Name elements -->
+ <field name="N_LAST" type="string" compare="always"/>
+ <field name="N_FIRST" type="string" compare="always"/>
+ <field name="N_MIDDLE" type="string" compare="always"/>
+ <field name="N_PREFIX" type="string" compare="conflict"/>
+ <field name="N_SUFFIX" type="string" compare="conflict"/>
+ <field name="NICKNAME" type="string" compare="conflict"/>
+ <field name="TITLE" type="string" compare="conflict" merge="fillempty"/>
+
+ <field name="FN" type="string" compare="conflict" merge="fillempty"/>
+ <field name="FILE-AS" type="string" compare="conflict" merge="fillempty"/>
+
+ <field name="GENDER" type="string" compare="conflict" merge="fillempty"/>
+
+ <!-- categories and classification -->
+ <field name="CATEGORIES" array="yes" type="string" compare="conflict"/>
+
+ <!-- organisation -->
+ <field name="ORG_NAME" type="string" compare="slowsync" merge="fillempty"/>
+ <field name="ORG_DIVISION" type="string" compare="conflict" merge="fillempty"/>
+ <field name="ORG_OFFICE" type="string" compare="conflict" merge="fillempty"/>
+ <field name="ORG_TEAM" type="string" compare="conflict" merge="fillempty"/>
+ <field name="ROLE" type="string" compare="conflict" merge="fillempty"/>
+
+ <!-- birthday and anniversary (not necessarily the same) -->
+ <field name="BDAY" type="date" compare="conflict" merge="fillempty"/>
+ <field name="ANNIVERSARY" type="date" compare="conflict" merge="fillempty"/>
+
+ <!-- telephone numbers -->
+ <field name="TEL" array="yes" type="telephone" compare="conflict"/>
+ <field name="TEL_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
+ <field name="TEL_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="TEL_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+ <field name="TEL_SLOT" array="yes" type="integer" compare="never"/> <!-- offset 3 -->
+
+ <!-- emails -->
+ <field name="EMAIL" array="yes" type="multiline" compare="conflict"/>
+ <field name="EMAIL_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
+ <field name="EMAIL_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="EMAIL_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+ <field name="EMAIL_SLOT" array="yes" type="integer" compare="never"/> <!-- offset 3 -->
+
+ <!-- web addresses -->
+ <field name="WEB" array="yes" type="string" compare="conflict"/>
+ <field name="WEB_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
+ <field name="WEB_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="WEB_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+
+ <!-- would be nicer to have as part of WEB, but parser/encoder does not support mapping
+ with more than one property per field -->
+ <field name="CALURI" array="yes" type="string" compare="conflict"/>
+ <field name="FBURL" array="yes" type="string" compare="conflict"/>
+ <field name="BLOGURL" array="yes" type="string" compare="conflict"/>
+ <field name="VIDEOURL" array="yes" type="string" compare="conflict"/>
+
+ <!-- related persons: should be turned into array, like WEB and CALURI/FBURL -->
+ <field name="MANAGER" type="string" compare="conflict"/>
+ <field name="ASSISTANT" type="string" compare="conflict"/>
+ <field name="SPOUSE" type="string" compare="conflict"/>
+
+ <!-- does this person want HTML mails? Valid values are TRUE/FALSE; a "boolean"
+ type would be useful, maybe add that later. -->
+ <field name="WANTS_HTML" type="string" compare="conflict"/>
+
+ <!-- chat handles: should be turned into one array, like WEB and CALURI/FBURL -->
+ <field name="AIM_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="AIM_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="GADUGADU_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="GADUGADU_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="GROUPWISE_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="GROUPWISE_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="ICQ_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="ICQ_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="JABBER_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="JABBER_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="MSN_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="MSN_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="YAHOO_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="YAHOO_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="SKYPE_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="SKYPE_SLOT" array="yes" type="string" compare="conflict"/>
+ <field name="SIP_HANDLE" array="yes" type="string" compare="conflict"/>
+ <field name="SIP_SLOT" array="yes" type="string" compare="conflict"/>
+
+ <!-- home address -->
+ <field name="ADR_STREET" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_ADDTL" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_STREET_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 (from ADR_STREET_FLAGS) -->
+ <field name="ADR_STREET_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="ADR_STREET_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+ <field name="ADR_POBOX" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_CITY" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_REG" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_ZIP" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_COUNTRY" array="yes" type="multiline" compare="conflict"/>
+
+ <!-- Note -->
+ <field name="NOTE" type="multiline" compare="conflict" merge="lines"/>
+
+ <!-- Photo -->
+ <field name="PHOTO" type="blob" compare="never" merge="fillempty"/>
+ <field name="PHOTO_TYPE" type="integer" compare="never" merge="fillempty"/>
+
+ </fieldlist>
--- /dev/null
+ <!-- vCard profile -->
+ <mimeprofile name="vCard" fieldlist="contacts">
+
+ <profile name="VCARD" nummandatory="0"> <!-- we allow records without "N" as Address book can store them -->
+ <property name="VERSION">
+ <value conversion="version"/>
+ </property>
+
+ <property onlyformode="standard" name="PRODID" mandatory="no">
+ <value conversion="prodid"/>
+ </property>
+
+ <property name="REV">
+ <value field="REV"/>
+ </property>
+
+ <property name="N" values="5" mandatory="yes"> <!-- Note: makes N parse and generate even if not in remote's CTCap -->
+ <value index="0" field="N_LAST"/>
+ <value index="1" field="N_FIRST"/>
+ <value index="2" field="N_MIDDLE"/>
+ <value index="3" field="N_PREFIX"/>
+ <value index="4" field="N_SUFFIX"/>
+ </property>
+
+ <property name="FN">
+ <value field="FN"/>
+ </property>
+
+ <property name="X-EVOLUTION-FILE-AS">
+ <value field="FILE-AS"/>
+ </property>
+
+ <property name="X-GENDER">
+ <value field="GENDER"/>
+ </property>
+
+ <!-- onlyformode="standard": not part of vCard 2.1, but some
+ peers (like the Funambol server) accept it anyway in
+ vCard 2.1 -->
+ <property name="NICKNAME">
+ <value field="NICKNAME"/>
+ </property>
+
+ <property name="TITLE">
+ <value field="TITLE"/>
+ </property>
+
+ <property name="CATEGORIES" values="list" valueseparator="," altvalueseparator=";" > <!-- non-standard, but 1:1 as in vCard 3.0 (NOT like in vCalendar 1.0, where separator is ";") -->
+ <value field="CATEGORIES"/>
+ <position field="CATEGORIES" repeat="array" increment="1" minshow="0"/>
+ </property>
+
+ <property name="ORG" values="4">
+ <value index="0" field="ORG_NAME"/>
+ <value index="1" field="ORG_DIVISION"/>
+ <value index="2" field="ORG_OFFICE"/>
+ <value index="3" field="ORG_TEAM"/>
+ </property>
+
+ <property name="ROLE">
+ <value field="ROLE"/>
+ </property>
+
+ <property name="TEL">
+ <value field="TEL"/>
+ <position field="TEL" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="TEL_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+ <enum name="VOICE" value="B3"/>
+ <enum name="CELL" value="B4"/>
+ <enum name="FAX" value="B5"/>
+ <enum name="PAGER" value="B6"/>
+ <enum name="PREF" value="B7"/>
+ <enum name="CAR" value="B8"/>
+ <enum name="X-EVOLUTION-CALLBACK" value="B9"/>
+ <enum name="X-EVOLUTION-RADIO" value="B10"/>
+ <enum name="X-EVOLUTION-TELEX" value="B11"/>
+ <enum name="X-EVOLUTION-TTYTDD" value="B12"/>
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="TEL_SLOT"/>
+ </parameter>
+ </property>
+
+ <property name="EMAIL">
+ <value field="EMAIL"/>
+ <position field="EMAIL" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="EMAIL_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+ <enum name="INTERNET" value="B3"/>
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="EMAIL_SLOT"/>
+ </parameter>
+ </property>
+
+ <property name="URL">
+ <value field="WEB"/>
+ <position field="WEB" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="WEB_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+ <enum name="PREF" value="B3"/>
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="CALURI" suppressempty="yes">
+ <value field="CALURI" show="yes"/>
+ </property>
+ <property name="FBURL" suppressempty="yes">
+ <value field="FBURL" show="yes"/>
+ </property>
+ <property name="X-EVOLUTION-BLOG-URL" suppressempty="yes">
+ <value field="BLOGURL" show="yes"/>
+ </property>
+ <property name="X-EVOLUTION-VIDEO-URL" suppressempty="yes">
+ <value field="VIDEOURL" show="yes"/>
+ </property>
+
+ <!-- item for SyncML server: EVOLUTION rule not active,
+ both X-EVOLUTION-MANAGER and X-MANAGER are sent.
+
+ item from SyncML server: EVOLUTION rule not active,
+ both X-EVOLUTION-MANAGER and X-MANAGER are checked,
+ but X-EVOLUTION-MANAGER later so that it overwrites
+ a value set earlier by X-MANAGER (if any). This is
+ a more or less arbitrary priority, chosen because
+ servers that know about SyncEvolution (ScheduleWorld,
+ Memotoo) use the X-EVOLUTION variant.
+
+ item to/from Evolution: EVOLUTION rule is active,
+ only X-EVOLUTION-MANAGER is used. -->
+ <property name="X-EVOLUTION-MANAGER" suppressempty="yes" delayedparsing="1">
+ <value field="MANAGER" show="yes"/>
+ </property>
+ <property name="X-MANAGER" suppressempty="yes" rule="EVOLUTION"/> <!-- disables the X-MANAGER for EVOLUTION -->
+ <property name="X-MANAGER" suppressempty="yes" rule="other">
+ <value field="MANAGER" show="yes"/>
+ </property>
+
+ <property name="X-EVOLUTION-ASSISTANT" suppressempty="yes" delayedparsing="1">
+ <value field="ASSISTANT" show="yes"/>
+ </property>
+ <property name="X-ASSISTANT" suppressempty="yes" rule="EVOLUTION"/>
+ <property name="X-ASSISTANT" suppressempty="yes" rule="other">
+ <value field="ASSISTANT" show="yes"/>
+ </property>
+
+ <property name="X-EVOLUTION-SPOUSE" suppressempty="yes" delayedparsing="1">
+ <value field="SPOUSE" show="yes"/>
+ </property>
+ <property name="X-SPOUSE" suppressempty="yes" rule="EVOLUTION"/>
+ <property name="X-SPOUSE" suppressempty="yes" rule="other">
+ <value field="SPOUSE" show="yes"/>
+ </property>
+
+ <property name="X-EVOLUTION-ANNIVERSARY" suppressempty="yes" delayedparsing="1">
+ <value field="ANNIVERSARY" show="yes"/>
+ </property>
+ <property name="X-ANNIVERSARY" suppressempty="yes" rule="EVOLUTION"/>
+ <property name="X-ANNIVERSARY" suppressempty="yes" rule="other">
+ <value field="ANNIVERSARY" show="yes"/>
+ </property>
+
+ <property name="X-MOZILLA-HTML">
+ <value field="WANTS_HTML" show="yes"/>
+ </property>
+
+ <property name="X-AIM" suppressempty="yes">
+ <value field="AIM_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="AIM_SLOT"/>
+ </parameter>
+ </property>
+ <property name="X-GADUGADU" suppressempty="yes">
+ <value field="GADUGADU_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="GADUGADU_SLOT"/>
+ </parameter>
+ </property>
+ <property name="X-GROUPWISE" suppressempty="yes">
+ <value field="GROUPWISE_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="GROUPWISE_SLOT"/>
+ </parameter>
+ </property>
+ <property name="X-ICQ" suppressempty="yes">
+ <value field="ICQ_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="ICQ_SLOT"/>
+ </parameter>
+ </property>
+ <property name="X-JABBER" suppressempty="yes">
+ <value field="JABBER_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="JABBER_SLOT"/>
+ </parameter>
+ </property>
+ <property name="X-MSN" suppressempty="yes">
+ <value field="MSN_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="MSN_SLOT"/>
+ </parameter>
+ </property>
+ <property name="X-YAHOO" suppressempty="yes">
+ <value field="YAHOO_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="YAHOO_SLOT"/>
+ </parameter>
+ </property>
+
+ <property name="X-SKYPE" suppressempty="yes">
+ <value field="SKYPE_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="SKYPE_SLOT"/>
+ </parameter>
+ </property>
+
+ <property name="X-SIP" suppressempty="yes">
+ <value field="SIP_HANDLE"/>
+ <parameter name="X-EVOLUTION-UI-SLOT" positional="no" show="yes">
+ <value field="SIP_SLOT"/>
+ </parameter>
+ </property>
+
+ <property name="ADR" values="7">
+ <value index="0" field="ADR_POBOX"/>
+ <value index="1" field="ADR_ADDTL"/>
+ <value index="2" field="ADR_STREET"/>
+ <value index="3" field="ADR_CITY"/>
+ <value index="4" field="ADR_REG"/>
+ <value index="5" field="ADR_ZIP"/>
+ <value index="6" field="ADR_COUNTRY"/>
+ <position field="ADR_POBOX" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="ADR_STREET_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="BDAY">
+ <value field="BDAY"/>
+ </property>
+
+ <property name="NOTE" filter="no">
+ <value field="NOTE"/>
+ </property>
+
+ <property name="PHOTO" filter="no">
+ <value field="PHOTO" conversion="BLOB_B64"/>
+ <parameter name="TYPE" default="no" show="yes">
+ <value field="PHOTO_TYPE">
+ <enum name="JPEG" value="0"/>
+ </value>
+ </parameter>
+ </property>
+
+ </profile>
+ </mimeprofile>
--- /dev/null
+
+
+ <!-- vCard 2.1 datatype, using vCard profile defined above -->
+ <datatype name="vCard21" basetype="vcard">
+ <version>2.1</version>
+ <use mimeprofile="vCard"/>
+ <incomingscript><![CDATA[
+ $VCARD_INCOMING_NAMECHANGE_SCRIPT
+ ]]></incomingscript>
+ </datatype>
+
+ <!-- vCard 3.0 datatype, using vCard profile defined above -->
+ <datatype name="vCard30" basetype="vcard">
+ <version>3.0</version>
+ <use mimeprofile="vCard"/>
+ <incomingscript><![CDATA[
+ $VCARD_INCOMING_NAMECHANGE_SCRIPT
+ ]]></incomingscript>
+ </datatype>
--- /dev/null
+ <!-- common field list for events and todos (both represented by vCalendar/iCalendar) -->
+ <fieldlist name="calendar">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="ISEVENT" type="integer" compare="always"/>
+
+ <field name="DMODIFIED" type="timestamp" compare="never" age="yes"/>
+ <field name="DCREATED" type="timestamp" compare="never"/>
+
+ <field name="DGENERATED" type="timestamp" compare="never"/>
+
+ <field name="UID" type="string" compare="never"/>
+
+ <field name="CATEGORIES" array="yes" type="string" compare="conflict" merge="fillempty"/>
+ <field name="CLASS" type="integer" compare="conflict" merge="fillempty"/>
+ <field name="TRANSP" type="integer" compare="conflict" merge="fillempty"/>
+
+ <field name="SUMMARY" type="multiline" compare="always"/>
+ <field name="DESCRIPTION" type="multiline" compare="slowsync" merge="lines"/>
+ <field name="LOCATION" type="multiline" compare="slowsync" merge="lines"/>
+ <field name="URL" type="url" compare="conflict"/>
+
+ <!-- recurrence rule block, fields must be in that order, including
+ DTSTART as last field !! -->
+ <field name="RR_FREQ" type="string" compare="conflict"/>
+ <field name="RR_INTERVAL" type="integer" compare="conflict"/>
+ <field name="RR_FMASK" type="integer" compare="conflict"/>
+ <field name="RR_LMASK" type="integer" compare="conflict"/>
+ <field name="RR_END" type="timestamp" compare="conflict"/>
+
+ <!-- Note: DTSTART/DTEND are compared in the <comparescript>,
+ therefore compare is set no "never" here -->
+ <field name="DTSTART" type="timestamp" compare="never"/>
+ <field name="DTEND" type="timestamp" compare="never"/>
+ <field name="DURATION" type="timestamp" compare="never"/>
+ <field name="COMPLETED" type="timestamp" compare="never"/>
+ <field name="DUE" type="timestamp" compare="never"/>
+
+ <field name="GEO_LAT" type="string" compare="never"/>
+ <field name="GEO_LONG" type="string" compare="never"/>
+
+ <field name="PRIORITY" type="integer" compare="conflict"/>
+ <field name="STATUS" type="integer" compare="conflict" merge="fillempty"/>
+ <field name="PERCENT_COMPLETE" type="integer" compare="conflict"/>
+
+ <field name="ALARM_TIME" type="timestamp" compare="conflict"/>
+ <field name="ALARM_SNOOZE" type="string" compare="conflict"/>
+ <field name="ALARM_REPEAT" type="string" compare="conflict"/>
+ <field name="ALARM_MSG" type="string" compare="conflict"/>
+ <field name="ALARM_ACTION" type="string" compare="conflict"/>
+ <field name="ALARM_REL" type="integer" compare="never"/>
+ <field name="ALARM_UID" type="string" compare="conflict"/>
+
+ <!-- non-standard -->
+ <field name="PARENT_UID" type="string" compare="never"/>
+
+ <!-- for events -->
+ <field name="EXDATES" array="yes" type="timestamp" compare="never"/>
+
+ <field name="ORIGSTART" array="no" type="timestamp" compare="never"/>
+ <field name="SEQNO" array="no" type="integer" compare="never"/>
+
+ <field name="ATTENDEES" array="yes" type="string" compare="never"/>
+ <field name="ATTENDEE_CNS" array="yes" type="string" compare="never"/>
+ <field name="ATTENDEE_PARTSTATS" array="yes" type="integer" compare="never"/>
+ <field name="ATTENDEE_ROLE" array="yes" type="integer" compare="never"/>
+ <field name="ATTENDEE_RSVP" array="yes" type="integer" compare="never"/>
+ <field name="ATTENDEE_LANG" array="yes" type="string" compare="never"/>
+ <field name="ATTENDEE_CUTYPE" array="yes" type="integer" compare="never"/>
+ <field name="ORGANIZER" array="no" type="string" compare="never"/>
+ <field name="ORGANIZER_CN" array="no" type="string" compare="never"/>
+
+ </fieldlist>
--- /dev/null
+ <!-- vCalendar with VTODO and VEVENT variants -->
+ <mimeprofile name="vCalendar" fieldlist="calendar">
+
+ <vtimezonegenmode>current</vtimezonegenmode>
+ <tzidgenmode>olson</tzidgenmode>
+
+ <profile name="VCALENDAR" nummandatory="1">
+
+ <property name="VERSION" mandatory="yes">
+ <value conversion="version"/>
+ </property>
+
+ <property onlyformode="standard" name="PRODID" mandatory="no">
+ <value conversion="prodid"/>
+ </property>
+
+ <property onlyformode="old" name="TZ" filter="false" suppressempty="yes">
+ <value field="DTSTART" conversion="tz"/>
+ </property>
+
+ <property onlyformode="old" name="DAYLIGHT" mode="daylight" filter="false" suppressempty="yes">
+ <value field="DTSTART" conversion="daylight"/>
+ </property>
+
+ <property name="GEO" values="2" suppressempty="yes" onlyformode="old" valueseparator=",">
+ <!-- LON,LAT in vCalendar 1.0 -->
+ <value index="0" field="GEO_LAT"/>
+ <value index="1" field="GEO_LONG"/>
+ </property>
+
+ <subprofile onlyformode="standard" name="VTIMEZONE" mode="vtimezones"/>
+
+ <!-- sub-profile for tasks -->
+ <subprofile name="VTODO" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="0">
+
+ <property name="LAST-MODIFIED" suppressempty="yes">
+ <value field="DMODIFIED"/>
+ </property>
+
+ <property name="DTSTAMP" suppressempty="yes" onlyformode="standard">
+ <value field="DGENERATED"/>
+ </property>
+
+ <property name="DCREATED" suppressempty="yes" onlyformode="old">
+ <value field="DCREATED"/>
+ </property>
+ <property name="CREATED" suppressempty="yes" onlyformode="standard">
+ <value field="DCREATED"/>
+ </property>
+
+ <property name="UID" suppressempty="yes">
+ <value field="UID"/>
+ </property>
+
+ <property name="SEQUENCE" suppressempty="yes">
+ <value field="SEQNO"/>
+ </property>
+
+ <property name="GEO" values="2" suppressempty="yes" onlyformode="standard" valueseparator=";">
+ <!-- LAT;LON in iCalendar 2.0 -->
+ <value index="0" field="GEO_LONG"/>
+ <value index="1" field="GEO_LAT"/>
+ </property>
+
+ <property onlyformode="standard" name="CATEGORIES" values="list" valueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property onlyformode="old" name="CATEGORIES" values="list" valueseparator=";" altvalueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property name="CLASS" suppressempty="yes">
+ <value field="CLASS">
+ <enum name="PUBLIC" value="0"/>
+ <enum name="PRIVATE" value="1"/>
+ <enum name="CONFIDENTIAL" value="2"/>
+ </value>
+ </property>
+
+ <property name="SUMMARY" mandatory="yes">
+ <value field="SUMMARY"/>
+ </property>
+
+ <!-- DESCRIPTION is an optional property and libical does not like
+ empty properties, so suppress it here. However, in the scripts
+ we ensure that the DESCRIPTION field should never be empty. -->
+ <property name="DESCRIPTION" suppressempty="yes" mandatory="no">
+ <value field="DESCRIPTION"/>
+ </property>
+
+ <property name="LOCATION" suppressempty="yes" mandatory="no">
+ <value field="LOCATION"/>
+ </property>
+
+ <property name="URL" suppressempty="yes" mandatory="no">
+ <value field="URL"/>
+ </property>
+
+ <property name="DTSTART" suppressempty="yes" delayedparsing="1">
+ <value field="DTSTART" conversion="autodate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DTSTART" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DTSTART" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="COMPLETED" suppressempty="yes" delayedparsing="1">
+ <value field="COMPLETED" conversion="autoenddate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="COMPLETED" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="COMPLETED" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="DUE" suppressempty="yes" delayedparsing="1">
+ <value field="DUE" conversion="autodate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DUE" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DUE" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="PRIORITY" suppressempty="yes">
+ <value field="PRIORITY"/>
+ </property>
+
+ <property name="STATUS" onlyformode="standard" suppressempty="yes">
+ <value field="STATUS" conversion="emptyonly">
+ <enum name="COMPLETED" value="0"/>
+ <enum name="NEEDS-ACTION" value="1"/>
+ <enum name="IN-PROCESS" value="2"/>
+ <enum name="CANCELLED" value="3"/>
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="SENT" value="8"/>
+ <enum name="CONFIRMED" value="9"/>
+ <enum name="DRAFT" value="10"/>
+ <enum name="FINAL" value="11"/>
+ </value>
+ </property>
+
+ <property name="STATUS" onlyformode="old" suppressempty="yes">
+ <value field="STATUS" conversion="emptyonly">
+ <enum name="COMPLETED" value="0"/>
+ <enum name="NEEDS ACTION" value="1"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="IN PROCESS" value="2"/>
+ <enum name="CANCELLED" value="3"/>
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="SENT" value="8"/>
+ <enum name="CONFIRMED" value="9"/>
+ <enum name="DRAFT" value="10"/>
+ <enum name="FINAL" value="11"/>
+ </value>
+ </property>
+
+ <property name="PERCENT-COMPLETE" onlyformode="standard" suppressempty="yes">
+ <value field="PERCENT_COMPLETE"/>
+ </property>
+
+ <!-- AALARM and DALARM both use the same fields -->
+ <property name="AALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+ <property name="DALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+
+ <subprofile onlyformode="standard" name="VALARM" nummandatory="1" field="ALARM_TIME">
+ <property name="TRIGGER" suppressempty="no" mandatory="yes">
+ <value field="ALARM_TIME"/>
+ <parameter name="VALUE" default="no" show="yes">
+ <value field="ALARM_TIME" conversion="FULLVALUETYPE"/>
+ </parameter>
+ <parameter name="RELATED" default="no" show="yes">
+ <value field="ALARM_REL">
+ <enum mode="ignore" value="0"/>
+ <enum name="START" value="1"/>
+ <enum name="END" value="2"/>
+ </value>
+ </parameter>
+ </property>
+ <property name="ACTION" suppressempty="yes" mandatory="yes">
+ <value field="ALARM_ACTION"/>
+ </property>
+ <property name="DESCRIPTION" suppressempty="yes">
+ <value field="ALARM_MSG"/>
+ </property>
+ <property name="REPEAT" suppressempty="yes">
+ <value field="ALARM_REPEAT"/>
+ </property>
+ <property name="X-EVOLUTION-ALARM-UID" suppressempty="yes">
+ <value field="ALARM_UID"/>
+ </property>
+ </subprofile>
+
+ <property onlyformode="old" name="RELATED-TO" suppressempty="yes">
+ <value field="PARENT_UID"/>
+ </property>
+
+ <property onlyformode="standard" name="RELATED-TO" suppressempty="yes">
+ <value field="PARENT_UID"/>
+ <parameter onlyformode="standard" name="RELTYPE" default="no" positional="yes" show="yes">
+ <value>
+ <enum name="PARENT"/>
+ <enum mode="defaultvalue" name="other"/>
+ </value>
+ <position hasnot="other" shows="PARENT" field="PARENT_UID"/>
+ </parameter>
+ </property>
+
+ </subprofile>
+
+ <!-- sub-profile for event -->
+ <subprofile name="VEVENT" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="1">
+
+ <property name="STATUS" suppressempty="yes" onlyformode="old">
+ <value field="STATUS" conversion="emptyonly">
+ <enum name="COMPLETED" value="0"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="NEEDS ACTION" value="1"/>
+ <enum name="CANCELLED" value="3"/>
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="SENT" value="8"/>
+ <enum name="CONFIRMED" value="9"/>
+ <enum name="FINAL" value="11"/>
+ </value>
+ </property>
+
+ <property name="STATUS" suppressempty="yes" onlyformode="standard">
+ <value field="STATUS" conversion="emptyonly">
+ <enum name="CANCELLED" value="3"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="CONFIRMED" value="9"/>
+ </value>
+ </property>
+
+ <property name="LAST-MODIFIED" suppressempty="yes">
+ <value field="DMODIFIED"/>
+ </property>
+
+ <property name="DTSTAMP" suppressempty="yes" onlyformode="standard">
+ <value field="DGENERATED"/>
+ </property>
+
+ <property name="DCREATED" suppressempty="yes" onlyformode="old">
+ <value field="DCREATED"/>
+ </property>
+ <property name="CREATED" suppressempty="yes" onlyformode="standard">
+ <value field="DCREATED"/>
+ </property>
+
+
+ <property name="UID" suppressempty="yes">
+ <value field="UID"/>
+ </property>
+
+ <property name="SEQUENCE" suppressempty="yes">
+ <value field="SEQNO"/>
+ </property>
+
+ <property name="GEO" values="2" suppressempty="yes" onlyformode="standard" valueseparator=";">
+ <!-- LAT;LON in iCalendar 2.0 -->
+ <value index="0" field="GEO_LONG"/>
+ <value index="1" field="GEO_LAT"/>
+ </property>
+
+ <property onlyformode="standard" name="CATEGORIES" values="list" valueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property onlyformode="old" name="CATEGORIES" values="list" valueseparator=";" altvalueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property name="CLASS" suppressempty="yes">
+ <value field="CLASS">
+ <enum name="PUBLIC" value="0"/>
+ <enum name="PRIVATE" value="1"/>
+ <enum name="CONFIDENTIAL" value="2"/>
+ </value>
+ </property>
+
+
+ <property name="TRANSP" suppressempty="yes" onlyformode="standard">
+ <value field="TRANSP">
+ <enum name="OPAQUE" value="0"/>
+ <enum name="TRANSPARENT" value="1"/>
+ <enum name="TENTATIVE" value="2"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->
+ <enum name="OUT_OF_OFFICE" value="3"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->
+ <enum mode="defaultvalue" value="0"/>
+ </value>
+ </property>
+ <property name="TRANSP" suppressempty="yes" onlyformode="old">
+ <value field="TRANSP"/> <!-- directly numeric in vCalendar 1.0 -->
+ </property>
+
+
+ <property name="PRIORITY" suppressempty="yes">
+ <value field="PRIORITY"/>
+ </property>
+
+ <property name="SUMMARY" mandatory="yes">
+ <value field="SUMMARY"/>
+ </property>
+
+ <!-- DESCRIPTION is an optional property and libical does not like
+ empty properties, so suppress it here. However, in the scripts
+ we ensure that the DESCRIPTION field should never be empty. -->
+ <property name="DESCRIPTION" suppressempty="yes" mandatory="no">
+ <value field="DESCRIPTION"/>
+ </property>
+
+ <property name="LOCATION" suppressempty="yes" mandatory="no">
+ <value field="LOCATION"/>
+ </property>
+
+ <property name="DTSTART" suppressempty="yes" delayedparsing="1">
+ <value field="DTSTART" conversion="autodate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DTSTART" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DTSTART" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <!-- recurrence rule (with delayed parsing, as it is dependent on DTSTART) -->
+ <property name="RRULE" suppressempty="yes" delayedparsing="2">
+ <!-- Note: RR_FREQ is the beginning of a block of fields
+ suitable for the "rrule" conversion mode -->
+ <value field="RR_FREQ" conversion="rrule"/>
+ </property>
+
+ <!-- Symbian uses this, so it might make the client work with symbian-prepared servers better -->
+ <property name="X-RECURRENCE-ID" suppressempty="yes" onlyformode="old">
+ <value field="ORIGSTART" conversion="autodate"/>
+ </property>
+
+ <property name="RECURRENCE-ID" suppressempty="yes" onlyformode="standard" delayedparsing="1">
+ <value field="ORIGSTART" conversion="autodate"/>
+ <parameter name="TZID" default="no" show="yes">
+ <value field="ORIGSTART" conversion="TZID"/>
+ </parameter>
+ <parameter name="VALUE" default="no" show="yes">
+ <value field="ORIGSTART" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <!-- ScheduleWorld has a problem (bugzilla.moblin.org #2226)
+ with the EXDATE:value1,value2 format (correct in iCalendar 2.0):
+ as a workaround, accept all valid formats plus ; but
+ generate separate properties with one value each. -->
+ <property name="EXDATE" values="expandedlist" suppressempty="yes" onlyformode="standard" delayedparsing="1" valueseparator="," altvalueseparator=";">
+ <value field="EXDATES"/>
+ <position field="EXDATES" repeat="array" increment="1" minshow="0"/>
+ <parameter name="TZID" default="no" show="yes">
+ <value field="EXDATES" conversion="TZID"/>
+ </parameter>
+ </property>
+
+ <property name="EXDATE" values="list" suppressempty="yes" onlyformode="old" delayedparsing="1" valueseparator=";" altvalueseparator=",">
+ <value field="EXDATES"/>
+ <position field="EXDATES" repeat="array" increment="1" minshow="0"/>
+ </property>
+
+
+ <property name="DTEND" suppressempty="yes" delayedparsing="1">
+ <value field="DTEND" conversion="autoenddate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DTEND" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DTEND" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="DURATION" suppressempty="yes" delayedparsing="1" onlyformode="standard">
+ <value field="DURATION"/>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="no">
+ <value field="DURATION" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="ATTENDEE" suppressempty="yes" onlyformode="old">
+ <value field="ATTENDEES"/>
+ <parameter name="ROLE" default="no" positional="yes" show="yes">
+ <value>
+ <enum name="ORGANIZER"/>
+ </value>
+ <position has="ORGANIZER" field="ORGANIZER" overwriteempty="yes"/>
+ <position hasnot="ORGANIZER" field="ATTENDEES" repeat="array" increment="1" overwriteempty="yes"/>
+ </parameter>
+ <parameter name="STATUS" default="no" show="yes">
+ <value field="ATTENDEE_PARTSTATS">
+ <enum name="NEEDS ACTION" value="1"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="ATTENDEE" suppressempty="yes" onlyformode="standard">
+ <value field="ATTENDEES" conversion="mailto"/>
+ <position field="ATTENDEES" repeat="array" increment="1" minshow="0"/>
+ <parameter name="CN" default="no" show="yes" shownonempty="yes">
+ <value field="ATTENDEE_CNS"/>
+ </parameter>
+ <parameter name="PARTSTAT" default="no" show="yes">
+ <value field="ATTENDEE_PARTSTATS">
+ <enum name="NEEDS-ACTION" value="1"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ </value>
+ </parameter>
+ <parameter name="ROLE" default="no" show="yes">
+ <value field="ATTENDEE_ROLE">
+ <enum name="CHAIR" value="1"/>
+ <enum name="REQ-PARTICIPANT" value="2"/>
+ <enum name="OPT-PARTICIPANT" value="3"/>
+ <enum name="NON-PARTICIPANT" value="4"/>
+ </value>
+ </parameter>
+ <parameter name="RSVP" default="no" show="yes">
+ <value field="ATTENDEE_RSVP">
+ <enum name="TRUE" value="1"/>
+ <enum name="FALSE" value="0"/>
+ </value>
+ </parameter>
+ <parameter name="LANGUAGE" show="yes">
+ <value field="ATTENDEE_LANG"/>
+ </parameter>
+ <parameter name="CUTYPE" default="no" show="yes">
+ <value field="ATTENDEE_CUTYPE">
+ <enum name="INDIVIDUAL" value="1"/>
+ <enum name="GROUP" value="2"/>
+ <enum name="RESOURCE" value="3"/>
+ <enum name="ROOM" value="4"/>
+ <enum name="UNKNOWN" value="5"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="ORGANIZER" suppressempty="yes" onlyformode="standard">
+ <value field="ORGANIZER" conversion="mailto"/>
+ <parameter name="CN" default="no" show="yes">
+ <value field="ORGANIZER_CN"/>
+ </parameter>
+ </property>
+
+ <!-- AALARM and DALARM both use the same fields -->
+ <property name="AALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+ <property name="DALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+
+ <subprofile onlyformode="standard" name="VALARM" nummandatory="1" field="ALARM_TIME">
+ <property name="TRIGGER" suppressempty="no" mandatory="yes">
+ <value field="ALARM_TIME"/>
+ <parameter name="VALUE" default="no" show="yes">
+ <value field="ALARM_TIME" conversion="FULLVALUETYPE"/>
+ </parameter>
+ <parameter name="RELATED" default="no" show="yes">
+ <value field="ALARM_REL">
+ <enum mode="ignore" value="0"/>
+ <enum name="START" value="1"/>
+ <enum name="END" value="2"/>
+ </value>
+ </parameter>
+ </property>
+ <property name="ACTION" suppressempty="yes" mandatory="yes">
+ <value field="ALARM_ACTION"/>
+ </property>
+ <property name="DESCRIPTION" suppressempty="yes">
+ <value field="ALARM_MSG"/>
+ </property>
+ <property name="REPEAT" suppressempty="yes">
+ <value field="ALARM_REPEAT"/>
+ </property>
+ <property name="X-EVOLUTION-ALARM-UID" suppressempty="yes">
+ <value field="ALARM_UID"/>
+ </property>
+ </subprofile>
+
+ </subprofile>
+
+ </profile>
+ </mimeprofile>
+
--- /dev/null
+ <!-- vCalendar 1.0 datatype, using vCalendar profile defined above -->
+ <datatype name="vCalendar10" basetype="vcalendar">
+ <version>1.0</version>
+ <use mimeprofile="vCalendar"/>
+
+ <incomingscript><![CDATA[
+ $VCALENDAR_INCOMING_SCRIPT
+ ]]></incomingscript>
+
+ <outgoingscript><![CDATA[
+ $VCALENDAR_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ </datatype>
+
+
+ <!-- iCalendar 2.0 datatype, using vCalendar profile defined above -->
+ <datatype name="iCalendar20" basetype="vcalendar">
+ <version>2.0</version>
+ <use mimeprofile="vCalendar"/>
+
+ <incomingscript><![CDATA[
+ $VCALENDAR_INCOMING_SCRIPT
+ ]]></incomingscript>
+
+ <outgoingscript><![CDATA[
+ $VCALENDAR_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ </datatype>
+
--- /dev/null
+ <!-- list of internal fields representing plain text note data -->
+ <fieldlist name="Note">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="SUBJECT" type="multiline" compare="always"/>
+ <field name="TEXT" type="multiline" compare="conflict" merge="lines"/>
+ </fieldlist>
+
--- /dev/null
+ <textprofile name="Note" fieldlist="Note">
+ <linemap field="SUBJECT">
+ <numlines>1</numlines>
+ <inheader>false</inheader>
+ <allowempty>true</allowempty>
+ <filterkeyword>SUBJECT</filterkeyword>
+ </linemap>
+ <linemap field="TEXT">
+ <numlines>0</numlines>
+ <inheader>false</inheader>
+ <allowempty>true</allowempty>
+ </linemap>
+ </textprofile>
+
--- /dev/null
+ <datatype name="note10" basetype="text">
+ <use profile="Note"/>
+ <typestring>text/plain</typestring>
+ <versionstring>1.0</versionstring>
+ </datatype>
+
+ <datatype name="note11" basetype="text">
+ <use profile="Note"/>
+ <typestring>text/plain</typestring>
+ <versionstring>1.1</versionstring>
+ </datatype>
+
--- /dev/null
+ <!-- list of internal fields representing vBookmark data -->
+ <fieldlist name="bookmarks">
+ <field name="REV" type="timestamp" compare="never" age="yes"/>
+ <field name="SYNCLVL" type="integer" compare="never"/>
+
+ <!-- Name -->
+ <field name="TITLE" type="string" compare="always"/>
+
+ <!-- categories and classification -->
+ <field name="CATEGORIES" type="string" compare="conflict" merge="fillempty"/>
+ <field name="CLASS" type="string" compare="conflict" merge="fillempty"/>
+
+ <!-- web addresses -->
+ <field name="URL" type="url" compare="slowsync" merge="fillempty"/>
+
+ <!-- Note -->
+ <field name="NOTE" type="multiline" compare="conflict" merge="lines"/>
+
+ </fieldlist>
+
--- /dev/null
+ <!-- vBookmark profile -->
+ <mimeprofile name="vBookmark" fieldlist="bookmarks">
+
+ <profile name="VBKM" nummandatory="0">
+ <property name="VERSION">
+ <value conversion="version"/>
+ </property>
+
+ <property name="X-LAST-MODIFIED">
+ <value field="REV"/>
+ </property>
+
+ <property name="TITLE">
+ <value field="TITLE"/>
+ </property>
+
+ <property name="URL">
+ <value field="URL"/>
+ </property>
+
+ <!-- non-standard properties -->
+
+ <!-- inherit CATEGORIES from vCard 3.0, i.e. comma separated -->
+ <property name="CATEGORIES" values="list" valueseparator="," altvalueseparator=";">
+ <value field="CATEGORIES" combine=","/>
+ </property>
+
+ <property name="CLASS" suppressempty="yes">
+ <value field="CLASS"/>
+ </property>
+
+ <property name="NOTE" filter="no">
+ <value field="NOTE"/>
+ </property>
+
+ </profile>
+ </mimeprofile>
+
--- /dev/null
+ <!-- vBookmark datatype, using vBookmark profile defined above -->
+ <datatype name="vBookmark10" basetype="mimedir">
+ <typestring>text/x-vbookmark</typestring>
+ <versionstring>1.0</versionstring>
+ <use profile="vBookmark"/>
+ </datatype>
+
--- /dev/null
+ <!-- list of internal fields representing email data -->
+ <fieldlist name="email">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="MODIFIED" type="timestamp" compare="never" age="yes"/>
+ <field name="SENDER" type="multiline" compare="always"/>
+ <field name="RECEIVER" type="multiline" compare="always"/>
+ <field name="CARBONCOPY" type="multiline" compare="always"/>
+ <field name="BLINDCARBONCOPY" type="multiline" compare="always"/>
+ <field name="REPLY_TO" type="multiline" compare="never"/>
+ <field name="SUBJECT" type="multiline" compare="always"/>
+ <field name="PRIORITY" type="integer" compare="never"/>
+ <field name="MAILDATE" type="timestamp" compare="never"/>
+ <field name="STATUS" type="string" compare="never"/>
+ <field name="FOLDER" type="string" compare="conflict"/>
+ <field name="ISREAD" type="string" compare="never"/>
+ <field name="LIMIT" type="integer" compare="never"/>
+ <field name="BODY" type="multiline" compare="never"/>
+ <field name="ATT_COUNT" type="integer" compare="never"/>
+ <field name="ATT_NAMES" array="yes" type="string" compare="never"/>
+ <field name="ATT_MIMETYPES" array="yes" type="string" compare="never"/>
+ <field name="ATT_SIZES" array="yes" type="integer" compare="never"/>
+ <field name="ATT_CONTENTS" array="yes" type="blob" compare="never"/>
+ </fieldlist>
+
--- /dev/null
+ <!-- this is the text profile used to generate and decode RFC2822/MIME-Multipart
+ email messages. -->
+ <textprofile name="rfc2822_email" fieldlist="email">
+
+ <mimemail>true</mimemail>
+ <!-- attachment configuration -->
+ <maxattachments>100</maxattachments>
+ <attachmentcountfield>ATT_COUNT</attachmentcountfield>
+ <attachmentmimetypesfield>ATT_MIMETYPES</attachmentmimetypesfield>
+ <attachmentsfield>ATT_CONTENTS</attachmentsfield>
+ <attachmentsizesfield>ATT_SIZES</attachmentsizesfield>
+ <attachmentnamesfield>ATT_NAMES</attachmentnamesfield>
+ <sizelimitfield>LIMIT</sizelimitfield>
+
+
+ <linemap field="SENDER">
+ <headertag>From:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>FROM</filterkeyword>
+ </linemap>
+
+ <linemap field="RECEIVER">
+ <headertag>To:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>TO</filterkeyword>
+ </linemap>
+
+ <linemap field="CARBONCOPY">
+ <headertag>Cc:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>CC</filterkeyword>
+ </linemap>
+
+ <linemap field="BLINDCARBONCOPY">
+ <headertag>Bcc:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>BCC</filterkeyword>
+ </linemap>
+
+ <linemap field="REPLY_TO">
+ <headertag>Reply-To:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="SUBJECT">
+ <headertag>Subject:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>SUBJECT</filterkeyword>
+ </linemap>
+
+ <linemap field="PRIORITY">
+ <headertag>X-Priority:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="MAILDATE">
+ <valuetype>date</valuetype>
+ <headertag>Date:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="STATUS">
+ <headertag>Status:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="FOLDER">
+ <headertag>X-Sync-Parent-Folder:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="ISREAD">
+ <headertag>X-Sync-Message-Read:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="MODIFIED">
+ <!-- note that this is a ISO8601 date -->
+ <headertag>X-Sync-Lastmodified:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="BODY">
+ <valuetype>body</valuetype>
+ <numlines>0</numlines>
+ <inheader>false</inheader>
+ <allowempty>true</allowempty>
+ </linemap>
+ </textprofile>
+
--- /dev/null
+ <!-- Note: This is a proprietary extension datatype for Synthesis AG Windows Mobile SyncML clients.
+ This format is a compressed form of the standard RFC2822 format. For one, the entire data
+ is compressed using the zip algorithm (<zippedbindata>), and secondly attachments are included
+ in binary form in the RFC2822 data stream rather than bandwidth wasting B64, adding a
+ "Content-Length:" header for each MIME part (<binaryparts>). -->
+
+ <datatype name="email_zipbin" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>application/x-zip-message</typestring> <!-- our own private zipped binary optimized format -->
+ <versionstring>1.1</versionstring>
+ <binaryparts>yes</binaryparts>
+ <zippedbindata>yes</zippedbindata>
+ <zipcompressionlevel>9</zipcompressionlevel> <!-- -1=default, 0=no compression, 1=fast & least effective ... 9=slow and most effective -->
+
+ <initscript><![CDATA[
+ $EMAIL_INIT_SCRIPT
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ $EMAIL_PROCESSITEM_SCRIPT
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ $EMAIL_MERGE_SCRIPT
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ $EMAIL_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ $EMAIL_FILTERINIT_SCRIPT
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ $EMAIL_FILTER_SCRIPT
+ ]]></filterscript>
+
+ </datatype>
+
--- /dev/null
+ <datatype name="email" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>text/message</typestring> <!-- this is P800-like -->
+ <versionstring>1.0</versionstring>
+
+ <initscript><![CDATA[
+ $EMAIL_INIT_SCRIPT
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ $EMAIL_PROCESSITEM_SCRIPT
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ $EMAIL_MERGE_SCRIPT
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ $EMAIL_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ $EMAIL_FILTERINIT_SCRIPT
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ $EMAIL_FILTER_SCRIPT
+ ]]></filterscript>
+
+ </datatype>
+
--- /dev/null
+ <datatype name="email_sonyericsson" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>message/rfc822</typestring> <!-- this is M600i/P990-like -->
+ <versionstring>1.0</versionstring>
+
+ <initscript><![CDATA[
+ $EMAIL_INIT_SCRIPT
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ $EMAIL_PROCESSITEM_SCRIPT
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ $EMAIL_MERGE_SCRIPT
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ $EMAIL_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ $EMAIL_FILTERINIT_SCRIPT
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ $EMAIL_FILTER_SCRIPT
+ ]]></filterscript>
+
+ </datatype>
+
--- /dev/null
+ <datatype name="email_nokia9500" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>message/x-rfc822</typestring> <!-- this is Nokia 9500/9300-like -->
+ <versionstring>1.0</versionstring>
+
+ <initscript><![CDATA[
+ INTEGER ITEMLIMIT;
+ // default limit is limit of session
+ ITEMLIMIT = SIZELIMIT();
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ INTEGER n;
+
+ // For Nokia Email, we must derive folder ID from source LocURI
+ // which has form "./somestrangenumber/folder/itemid"
+ // where folder can be "Inbox" or "Outbox"
+ if (FIND(REMOTEID(),"Inbox",0)!=UNASSIGNED) {
+ FOLDER="INBOX";
+ }
+ else if (FIND(REMOTEID(),"Outbox",0)!=UNASSIGNED) {
+ FOLDER="OUTBOX";
+ }
+ // pre-process item
+ if (UPPERCASE(FOLDER)=="INBOX") {
+ // In any case, prevent adding to inbox (delete remote items instead)
+ PREVENTADD();
+ // server always wins for inbox
+ CONFLICTSTRATEGY("server-wins");
+ if (SLOWSYNC()) {
+ // also prevent modifications in server
+ IGNOREUPDATE();
+ }
+ else {
+ // normal sync items going to inbox from client need special treatment
+ if (SYNCOP()=="add" || SYNCOP()=="replace") {
+ // make sure that existing server item will conflict with this item
+ if (LIMIT!=EMPTY && (LIMIT<0 || LIMIT>SIZELIMIT())) {
+ // force conflict only if this is a reload
+ FORCECONFLICT();
+ }
+ // make sure we never overwrite a body in the inbox
+ BODY = UNASSIGNED;
+ // delete always wins over replace in inbox (to avoid adds to inbox)
+ DELETEWINS();
+ }
+ }
+ }
+ else if (UPPERCASE(FOLDER)=="OUTBOX") {
+ // never try to change something in outbox
+ IGNOREUPDATE();
+ if (SYNCOP()!="delete") {
+ // - date of mail is NOW, set it such that a correct date is written to the DB
+ MAILDATE = DBNOW();
+ // MAILDATE = (INTEGER)DBNOW() - TIMEUNITS(120); // %%% backdate it 2 mins to make sure it does not get retransmitted
+ // - echo item as delete (this causes that it is moved to the "sent" folder in the 9500)
+ ECHOITEM("delete");
+ }
+ CONFLICTSTRATEGY("client-wins");
+ }
+ else {
+ // Other folder
+ // - silently discard incoming item for other folder than the above
+ // except if it is a delete
+ if (SYNCOP()!="delete")
+ REJECTITEM(0);
+ }
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ // pre-process item
+ if (UPPERCASE(LOOSING.FOLDER)!="OUTBOX") {
+ // non-outbox (especially inbox) needs special merge to accomplish reload feature
+ // - loosing item is client's, winning is server's
+ if (LOOSING.LIMIT!=EMPTY) {
+ // loosing (remote) item specifies a new limit, override winning's default
+ WINNING.LIMIT=LOOSING.LIMIT;
+ SETWINNINGCHANGED(TRUE);
+ }
+ // make sure winning has right folder
+ WINNING.FOLDER=LOOSING.FOLDER;
+ // make sure a set read-flag gets propagated to server
+ if (LOOSING.ISREAD=="true") WINNING.ISREAD="true";
+ // merge other fields normally
+ MERGEFIELDS();
+ // make sure body does not get re-written to local DB even if merge would cause local update
+ LOOSING.BODY=UNASSIGNED;
+ }
+ else {
+ // normal merging in other folders
+ MERGEFIELDS();
+ }
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ // we can only send to inbox or outbox
+ // - If we have no remote ID (=add command) prepare special Target item ID
+ // containing target folder.
+ if (REMOTEID()==EMPTY) {
+ if (UPPERCASE(FOLDER)=="INBOX") {
+ SETREMOTEID(REMOTEDBNAME()+"/Inbox/");
+ }
+ else if (UPPERCASE(FOLDER)=="OUTBOX") {
+ SETREMOTEID(REMOTEDBNAME()+"/Outbox/");
+ }
+ }
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ // check if we need to filter
+ INTEGER NEEDFILTER;
+
+ NEEDFILTER =
+ !DBHANDLESOPTS() && // only if DB cannot handle it
+ (STARTDATE()!=EMPTY); // and only if a start date is set (end date not needed as there are never future emails today)
+ SETFILTERALL(NEEDFILTER);
+ RETURN NEEDFILTER;
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ INTEGER PASSES;
+
+ // check if item passes filter
+ PASSES=FALSE;
+ // Filter out anything not for Inbox or Outbox
+ if (UPPERCASE(FOLDER)!="INBOX" && UPPERCASE(FOLDER)!="OUTBOX") RETURN FALSE;
+ // Emails pass if they have a MAILDATE on or later than start date
+ PASSES = MAILDATE>=STARTDATE();
+ RETURN PASSES;
+ ]]></filterscript>
+
+ </datatype>
--- /dev/null
+ <!-- path where logfiles are stored -->
+ <!-- <logpath platform="linux">/your/log/directory</logpath> -->
+ <logflushmode>buffered</logflushmode> <!-- buffered is fastest mode, but may loose data on process abort. Other options: "flush" (after every line) or "openclose" (safest, slowest, like in 2.x server) -->
+ <!-- per session log -->
+ <sessionlogs>yes</sessionlogs> <!-- by default, create a session log file for every sync session (might be disabled for special users/devices in scripts) -->
+ <!-- debug format options -->
+ <logformat>html</logformat> <!-- html is nicely colored and easily viewable with a web browser. Other options: "xml", "text" -->
+ <folding>auto</folding> <!-- dynamic folding of blocks enabled, automatically expanded or collapsed default. Other options: "none", "expanded", "collapsed" -->
+ <timestamp>yes</timestamp> <!-- show timestamps for structure elements in log -->
+ <timestampall>no</timestampall> <!-- don't show timestamp for every log line -->
+ <timedsessionlognames>yes</timedsessionlognames> <!-- session logs also have the session start timestamp in the filename - makes them more easily sortable -->
+ <!-- thread logging mode -->
+ <subthreadmode>separate</subthreadmode> <!-- write log info from subthreads into separate log files. Other options: "suppress" -->
+ <!-- basic debug level selection -->
+ <enable option="extended"/> <!-- "extended" is a good choice for start testing. For production, use "normal" or "minimal" -->
+ <!-- <enable option="normal"/> --> <!-- "normal" provides rich debug info, but still in reasonable size -->
+ <!-- <enable option="minimal"/> --> <!-- "minimal" just shows basic flow and error. Not suitable for debugging -->
+ <!-- <enable option="maximal"/> --> <!-- "maximal" can create VERY LARGE logs and cause HEAVY SLOWDOWN. Only for detail debugging -->
+ <!-- <enable option="all"/> --> <!-- "all" shows EVERYTHING possible, and way too much for any normal situation. For hardcore debugging ONLY! -->
+ <!-- additional debug info switches -->
+ <enable option="userdata"/> <!-- Make this <disable ...> if you don't want user data in the logs -->
+ <disable option="scripts"/> <!-- Make this <enable ...> to show script execution in logs -->
+ <disable option="match"/> <!-- Make this <enable ...> to show slow sync matching. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
+ <disable option="exotic"/> <!-- Make this <enable ...> to include very in-detail info. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
+ <!-- see manual for more debug info switches -->
+ <!-- global log options -->
+ <globallogs>no</globallogs> <!-- by default, do not log global session dispatching, creation etc. (not useful in multi-user operation) -->
+ <singlegloballog>no</singlegloballog> <!-- a new global log will be started for every start of the server/application -->
+ <!-- SyncML message dumping options -->
+ <msgdump>no</msgdump> <!-- do not dump syncml traffic 1:1 to files -->
+ <xmltranslate>no</xmltranslate> <!-- do not try to translate syncml traffic into XML (DO NOT SET THIS OPTION IN PRODUCTIVE SERVERS!) -->
--- /dev/null
+ <remoterule name="ZYB">
+ <manufacturer>ZYB</manufacturer>
+ <model>ZYB</model>
+ <!-- information to disable anchors checking -->
+ <lenientmode>yes</lenientmode>
+ </remoterule>
+
--- /dev/null
+ <remoterule name="EVOLUTION">
+ <deviceid>none - this rule is activated via its name in MAKE/PARSETEXTWITHPROFILE() macro calls</deviceid>
+ </remoterule>
--- /dev/null
+ <remoterule name="t39m">
+ <!-- Rule for Ericsson T39m client -->
+ <manufacturer>Ericsson</manufacturer>
+ <software>R1A</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>Ericsson T39m</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="t68">
+ <!-- Rule for Ericsson T68 client -->
+ <manufacturer>Ericsson</manufacturer>
+ <software>R1B</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>Ericsson T68</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="V3">
+ <!-- Rule for Motorola V3 -->
+ <manufacturer>Motorola*</manufacturer>
+ <model>V3</model>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <quote8bitcontent>yes</quote8bitcontent>
+ <nocontentfolding>yes</nocontentfolding>
+ <outputcharset>ANSI</outputcharset>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>Motorola V3</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="V3i">
+ <!-- Rule for Motorola V3i -->
+ <manufacturer>Motorola*</manufacturer>
+ <model>V3i</model>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <quote8bitcontent>yes</quote8bitcontent>
+ <nocontentfolding>yes</nocontentfolding>
+ <outputcharset>ANSI</outputcharset>
+ <descriptivename>Motorola V3i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6230">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6230</model>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6230</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9210">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9210</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 9210</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9210i">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9210i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 9210</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3220">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3220</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3220</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3230">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3230</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3230</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3600">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3600</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3600</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3620">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3620</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3620</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3650">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3650</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3650</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3660">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3660</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3660</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6260">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6260</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6260</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6600">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6600</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6600</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6620">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6620</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6620</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6630">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6630</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6630</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6670">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6670</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6670</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7250">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7250</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7250</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7250i">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7250i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7250i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7260">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7260</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7260</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7610">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7610</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7610</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7650">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7650</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7650</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="N-Gage">
+ <manufacturer>NOKIA</manufacturer>
+ <model>N-Gage</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia N-Gage</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="N-Gage QD">
+ <manufacturer>NOKIA</manufacturer>
+ <model>N-Gage QD</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia N-Gage QD</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9300">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9300</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <treatasutc>yes</treatasutc> <!-- needs 2.1.1 or later server -->
+ <descriptivename>Nokia 9300</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9500">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9500</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <treatasutc>yes</treatasutc> <!-- needs 2.1.1 or later server -->
+ <descriptivename>Nokia 9500</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="E90">
+ <manufacturer>NOKIA</manufacturer>
+ <model>E90</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <ignoredevinfmaxsize>yes</ignoredevinfmaxsize>
+ <descriptivename>Nokia E90</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="X">
+ <manufacturer>Sendo</manufacturer>
+ <model>X</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Sendo X</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SX1">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>SX1</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <!-- Note: SX1 crashes on contacts with empty properties -->
+ <noemptyproperties>yes</noemptyproperties>
+ <descriptivename>Siemens SX1</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="M55">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>M55</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens M55</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SL55">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>SL55</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens SL55</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="S55">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>S55</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens S55</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="S65">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>S65</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens S65</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SL65">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>SL65</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens SL65</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="K700">
+ <!-- Rule for SonyEricsson K700 (aka SEMC Phone) client -->
+ <manufacturer>SonyEricsson</manufacturer>
+ <model>SEMC Phone</model>
+ <software>R3B</software>
+
+ <!-- is a 1.1 client and claims UTC support, but it seems not to work ok
+ <forcelocaltime>yes</forcelocaltime>
+ -->
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>SonyEricsson K700</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="T610/T630">
+ <!-- Rule for SonyEricsson T610/T630 client -->
+ <manufacturer>SonyEricsson</manufacturer>
+ <software>R2B</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>SonyEricsson T610/T630</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in M600i vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your M600i is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your M600i has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ M600i devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the M600i is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="M600i">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>M600i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson M600i</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P800 vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P800 is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P800 has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P800 devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P800 is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P800">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P800</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P800</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P900 vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P900 is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P900 has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P900 devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P900 is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P900">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P900</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P900</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P910 vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P910 is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P910 has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P910 devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P910 is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P910">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P910</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P910</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P910i vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P910i is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P910i has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P910i devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P910i is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P910i">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P910i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P910i</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P990i vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P990i is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P990i has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P990i devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P990i is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P990i">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P990i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P990i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="t68i">
+ <!-- Rule for SonyEricsson T68i client -->
+ <manufacturer>SonyEricsson</manufacturer>
+ <software>R2A</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>SonyEricsson T68i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="Funambol_Outlook">
+ <!-- Rule for Funambol Outlook Sync Client -->
+ <model>Funambol Outlook Sync Client</model>
+
+ <lenientmode>yes</lenientmode> <!-- some status messages are missing at end of session -->
+ <descriptivename>Funambol Outlook Sync Client</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SyncJe_Outlook">
+ <!-- Rule for NextHaus SyncJe Outlook Edition -->
+ <model>SyncJe Outlook Edition</model>
+
+ <ignorectcap>yes</ignorectcap> <!-- can do contact photo sync, but is missing in CTCap -->
+ <descriptivename>NextHaus SyncJe Outlook Client</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <macro name="VCARD_BEFOREWRITE_SCRIPT_EVOLUTION"><![CDATA[
+ // a wordaround for cellphone in evolution. for incoming contacts, if there is only one CELL,
+ // strip the HOME or WORK flag from it. Evolution then should show it. */
+ INTEGER i, wanted, cell_phones;
+ i = 0;
+ cell_phones = 0;
+ while(i < SIZE(TEL_FLAGS)) {
+ // 0x10 is the flag of 'cell' type of telephone
+ if(TEL_FLAGS[i] & 0x10) {
+ cell_phones = cell_phones + 1;
+ wanted = i;
+ }
+ i = i + 1;
+ }
+ if(cell_phones == 1) {
+ TEL_FLAGS[wanted] = 0x10;
+ }
+
+ // Google sends TYPE=WORK and TYPE=HOME when it means
+ // normal VOICE phone numbers. Add that flag when
+ // importing into Evolution, because Evolution does not
+ // display the numbers without VOICE.
+ i = 0;
+ while(i < SIZE(TEL_FLAGS)) {
+ if(TEL_FLAGS[i] == 1 || TEL_FLAGS[i] == 2) {
+ TEL_FLAGS[i] = TEL_FLAGS[i] | 8;
+ }
+ i = i + 1;
+ }
+ ]]></macro>
--- /dev/null
+ <macro name="VCALENDAR_20TO10_PRIORITY_CONVERSION"><![CDATA[
+ //vCalendar10 has different interpretation from iCalendar20 in 'priority'.
+ //see mappings:
+ // Category vCalendar1.0 iCalendar2.0
+ // undefined 0 0
+ // high 1 1 ~ 4
+ // normal 2 5
+ // low 3 6 ~ bigger
+ if(PRIORITY<5 && PRIORITY>0) {
+ PRIORITY=1;
+ }else if(PRIORITY==5){
+ PRIORITY=2;
+ }else if(PRIORITY>5){
+ PRIORITY=3;
+ } // 0 is undefined and remains unchanged
+ ]]></macro>
+ <macro name="VCALENDAR_10TO20_PRIORITY_CONVERSION"><![CDATA[
+ if(PRIORITY==2) {
+ PRIORITY=5;
+ }else if(PRIORITY==3){
+ PRIORITY=7;
+ } //others remain unchanged
+ ]]></macro>
+ <macro name="VCALENDAR10_BEFOREWRITE_SCRIPT"><![CDATA[
+ $VCALENDAR_20TO10_PRIORITY_CONVERSION;
+ ]]></macro>
+ <macro name="VCALENDAR10_AFTERREAD_SCRIPT"><![CDATA[
+ $VCALENDAR_10TO20_PRIORITY_CONVERSION;
+ ]]></macro>
+
--- /dev/null
+ <macro name="VCARD_INCOMING_NAMECHANGE_SCRIPT"><![CDATA[
+ STRING tmp;
+ tmp=NORMALIZED(FN);
+ if (tmp==EMPTY){
+ tmp=N_FIRST;
+ if (N_MIDDLE != EMPTY) {
+ if (tmp != EMPTY) {
+ tmp = tmp + " ";
+ }
+ tmp = tmp + N_MIDDLE;
+ }
+ if (N_LAST != EMPTY) {
+ if (tmp != EMPTY) {
+ tmp = tmp + " ";
+ }
+ tmp = tmp + N_LAST;
+ }
+ FN = tmp;
+ }
+ ]]></macro>
+
--- /dev/null
+ <function><![CDATA[
+ // create a UID
+ string newuid() {
+ return "syuid" + NUMFORMAT(RANDOM(1000000),6,"0") + "." + (string)MILLISECONDS(NOW());
+ }
+ ]]></function>
+
+
--- /dev/null
+ <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
+
+ <macro name="VCALENDAR_INCOMING_SCRIPT"><![CDATA[
+ STRING MATCHES[];
+ STRING CAT,CN,EM;
+ INTEGER i;
+ // make sure we have all trailing and leading spaces eliminated
+ DESCRIPTION=NORMALIZED(DESCRIPTION);
+ SUMMARY=NORMALIZED(SUMMARY);
+ // make sure that we have a DESCRIPTION
+ if (DESCRIPTION==EMPTY) DESCRIPTION=SUMMARY;
+ // calendar or todo
+ if (ISEVENT) {
+ // VEVENT
+ // - handle duration cases
+ if (ISDURATION(DURATION)) {
+ if (DTEND==EMPTY) DTEND = DTSTART + DURATION;
+ if (DTSTART==EMPTY) DTSTART = DTEND - DURATION;
+ }
+ // - detect alldays in vCalendar 1.0 (0:00-0:00 or 23:59 localtime)
+ i = ALLDAYCOUNT(DTSTART,DTEND,TRUE);
+ if (ITEMDATATYPE()=="vCalendar10" && i>0) {
+ // DTSTART and DTEND represent allday event, make them date-only values
+ // - convert start to user zone (or floating) so it represents midnight
+ DTSTART = CONVERTTOUSERZONE(DTSTART);
+ MAKEALLDAY(DTSTART,DTEND,i);
+ }
+ else {
+ // iCalendar 2.0 - only if DTSTART is a date-only value this really is an allday
+ if (ISDATEONLY(DTSTART)) {
+ // reshape to make sure we don't have invalid zero-duration alldays (old OCS 9 servers)
+ MAKEALLDAY(DTSTART,DTEND,i);
+ }
+ }
+
+ // Make sure that all EXDATE times are in the same timezone as the start
+ // time. Some servers send them as UTC, which is all fine and well, but
+ // only if the timezone definition doesn't change. Also, libical does not
+ // handle such UTC EXDATEs, so let's convert it while the UTC and
+ // time zone definition (hopefully) are in sync.
+ if (TIMEZONE(DTSTART) != "UTC" && !ISFLOATING(DTSTART)) {
+ i = 0;
+ timestamp exdate;
+ while (i<SIZE(EXDATES)) {
+ exdate = EXDATES[i];
+ if (!ISDATEONLY(exdate) &&
+ (TIMEZONE(exdate) == "UTC" || ISFLOATING(exdate))) {
+ // "unfloat" floating time stamps: not sure whether that occcurs
+ // in practice, but it looks as wrong as UTC EXDATEs
+ EXDATES[i] = CONVERTTOZONE(exdate,DTSTART,TRUE);
+ }
+ i=i+1;
+ }
+ }
+ // If vcalendar1.0, rrule is not secondly, minutely, or hourly, we strip time information
+ // and only reserve date information
+ if (ITEMDATATYPE()=="vCalendar10" && RR_FREQ!="h" && RR_FREQ!="m" && RR_FREQ!="s") {
+ timestamp exdate;
+ i = 0;
+ while (i<SIZE(EXDATES)) {
+ exdate = EXDATES[i];
+ if (!ISDATEONLY(exdate)) {
+ EXDATES[i] = DATEONLY(exdate);
+ }
+ i=i+1;
+ }
+ }
+
+ // - shape attendees (and make sure ATTENDEES[] is assigned even for empty email addresses)
+ i=0;
+ while(i<SIZE(ATTENDEES) || i<SIZE(ATTENDEE_CNS)) {
+ PARSEEMAILSPEC(ATTENDEES[i], CN, EM);
+ ATTENDEES[i] = EM; // pure email address
+ // in case we have no specific common name, use the one extracted from the email
+ // This catches the vCalendar 1.0 case and eventually ill-formed iCalendar 2.0 as well
+ if (ATTENDEE_CNS[i]==EMPTY)
+ ATTENDEE_CNS[i]=CN;
+ // default participation status to needs-action
+ if (ATTENDEE_PARTSTATS[i]==EMPTY)
+ ATTENDEE_PARTSTATS[i]=1; // 1=needs action
+ i=i+1;
+ }
+ // - shape organizer
+ PARSEEMAILSPEC(ORGANIZER, CN, EM);
+ ORGANIZER = EM; // pure email address
+ if (ORGANIZER_CN==EMPTY)
+ ORGANIZER_CN=CN;
+ }
+ else {
+ // VTODO
+ // - make sure we have at least a summary
+ if (SUMMARY==EMPTY) SUMMARY=DESCRIPTION; // use description if we don't have a summary
+ if (SUMMARY==EMPTY) SUMMARY="unnamed"; // set dummy summary if we still don't have one
+ // due shaping for non-iCalendar 2.0
+ if (ITEMDATATYPE()=="vCalendar10" && ALLDAYCOUNT(DUE,DUE,TRUE,TRUE)>0) {
+ DUE = DATEONLY(DUE);
+ }
+ if (ITEMDATATYPE()=="vCalendar10") {
+ $VCALENDAR_10TO20_PRIORITY_CONVERSION;
+ }
+ }
+ // a workaround for funambol: adding 'action' for 'alarm'
+ if (ITEMDATATYPE()=="iCalendar20") {
+ if (ALARM_TIME!=EMPTY && ALARM_ACTION==EMPTY) {
+ ALARM_ACTION = "DISPLAY";
+ }
+ }
+ ]]></macro>
+
+
+ <macro name="VCALENDAR_OUTGOING_SCRIPT"><![CDATA[
+ // set UTC time of generation for iCalendar 2.0 DTSTAMP
+ DGENERATED = NOW();
+ // make sure we have all trailing and leading spaces eliminated
+ DESCRIPTION=NORMALIZED(DESCRIPTION);
+ SUMMARY=NORMALIZED(SUMMARY);
+ if (ISEVENT) {
+ // VEVENT
+ // - combine attendee email address and common name into single string for vCalendar 1.0
+ if (ITEMDATATYPE()=="vCalendar10") {
+ i=0;
+ while(i<SIZE(ATTENDEES)) {
+ ATTENDEES[i] = MAKEEMAILSPEC(ATTENDEE_CNS[i], ATTENDEES[i]);
+ i=i+1;
+ }
+ ORGANIZER = MAKEEMAILSPEC(ORGANIZER_CN, ORGANIZER);
+ }
+ }
+ else {
+ // VTODO
+ // interal representation is iCalendar20
+ if (ITEMDATATYPE()=="vCalendar10") {
+ $VCALENDAR_20TO10_PRIORITY_CONVERSION;
+ }
+ }
+ // make sure we have at least a summary
+ if (SUMMARY==EMPTY) SUMMARY=SUBSTR(DESCRIPTION,0,32); // derive from description
+ if (SUMMARY==EMPTY) SUMMARY="unnamed"; // in case description is empty as well
+ // make sure that we have a DESCRIPTION
+ if (DESCRIPTION==EMPTY) DESCRIPTION=SUMMARY;
+ // do NOT send duration (some servers crash when doing so)
+ DURATION = UNASSIGNED;
+ // shape alarm
+ if (ALARM_TIME!=EMPTY) {
+ if (ITEMDATATYPE()=="iCalendar20") {
+ if (ALARM_ACTION==EMPTY) ALARM_ACTION = "AUDIO";
+ }
+ else {
+ if (ALARM_MSG==EMPTY) ALARM_MSG="alarm";
+ }
+ }
+ ]]></macro>
--- /dev/null
+ <looptimeout>5</looptimeout>
+
--- /dev/null
+ <!-- The following email handling scripts are defined as script MACROS because they
+ are used in multiple <datatype> definitions below. This avoids duplicating these
+ script's source code in the config file -->
+
+ <macro name="EMAIL_INIT_SCRIPT"><![CDATA[
+ INTEGER ITEMLIMIT;
+ // default limit is limit of session
+ ITEMLIMIT = SIZELIMIT();
+ ]]></macro>
+
+
+ <macro name="EMAIL_PROCESSITEM_SCRIPT"><![CDATA[
+ // pre-process item
+ if (UPPERCASE(FOLDER)=="INBOX") {
+ // In any case, prevent adding to inbox (delete remote items instead)
+ PREVENTADD();
+ // server always wins for inbox
+ CONFLICTSTRATEGY("server-wins");
+ if (SLOWSYNC()) {
+ // also prevent modifications in server
+ IGNOREUPDATE();
+ }
+ else {
+ // normal sync items going to inbox from client need special treatment
+ if (SYNCOP()=="add" || SYNCOP()=="replace") {
+ // make sure that existing server item will conflict with this item
+ if (LIMIT!=EMPTY && (LIMIT<0 || LIMIT>SIZELIMIT())) {
+ // force conflict only if this is a reload
+ FORCECONFLICT();
+ }
+ // make sure we never overwrite a body in the inbox
+ BODY = UNASSIGNED;
+ // delete always wins over replace in inbox (to avoid adds to inbox)
+ DELETEWINS();
+ }
+ }
+ }
+ else if (UPPERCASE(FOLDER)=="OUTBOX") {
+ // never try to change something in outbox
+ IGNOREUPDATE();
+ if (SYNCOP()!="delete") {
+ // - date of mail is NOW, set it such that a correct date is written to the DB
+ MAILDATE = DBNOW();
+ // MAILDATE = (INTEGER)DBNOW() - TIMEUNITS(120); // %%% backdate it 2 mins to make sure it does not get retransmitted
+ // - echo item as replace (to force-move it to the sent folder)
+ ECHOITEM("replace");
+ }
+ CONFLICTSTRATEGY("client-wins");
+ }
+ else if (UPPERCASE(FOLDER)=="SENT") {
+ // never try to change something in sent folder
+ IGNOREUPDATE();
+ // Server has precedence in case of conflicts
+ CONFLICTSTRATEGY("server-wins");
+ // Implement reload capability for sent items as well
+ if (SLOWSYNC()) {
+ // do not add new sent items to the server in slowsync
+ PREVENTADD(); // causes extra sent items on the client to be deleted
+ }
+ else {
+ // make sure that existing server item will conflict with this item
+ if (SYNCOP()=="replace") {
+ if (LIMIT!=EMPTY && (LIMIT<0 || LIMIT>SIZELIMIT())) {
+ // force conflict only if this is a reload
+ FORCECONFLICT();
+ REJECTITEM(200); // but do not process the item further
+ }
+ else {
+ // silently ignore other types of changes
+ REJECTITEM(200);
+ }
+ // make sure we never overwrite a body in the sent folder
+ BODY = UNASSIGNED;
+ }
+ }
+ }
+ else {
+ // Other folder
+ // - silently discard incoming item for other folder than the above
+ // except if it is a delete
+ if (SYNCOP()!="delete")
+ REJECTITEM(0);
+ }
+ ]]></macro>
+
+
+ <macro name="EMAIL_MERGE_SCRIPT"><![CDATA[
+ // pre-process item
+ if (UPPERCASE(LOOSING.FOLDER)!="OUTBOX") {
+ // non-outbox (especially inbox) needs special merge to accomplish reload feature
+ // - loosing item is client's, winning is server's
+ if (LOOSING.LIMIT!=EMPTY) {
+ // loosing (remote) item specifies a new limit, override winning's default
+ WINNING.LIMIT=LOOSING.LIMIT;
+ SETWINNINGCHANGED(TRUE);
+ }
+ // make sure winning has right folder
+ WINNING.FOLDER=LOOSING.FOLDER;
+ // make sure a set read-flag gets propagated to server
+ if (LOOSING.ISREAD=="true") WINNING.ISREAD="true";
+ // merge other fields normally
+ MERGEFIELDS();
+ // make sure body does not get re-written to local DB even if merge would cause local update
+ LOOSING.BODY=UNASSIGNED;
+ }
+ else {
+ // normal merging in other folders
+ MERGEFIELDS();
+ }
+ ]]></macro>
+
+ <macro name="EMAIL_OUTGOING_SCRIPT"><![CDATA[
+ // pre-process item
+ if (UPPERCASE(FOLDER)=="OUTBOX") {
+ // writing to outbox is always the ECHOITEM
+ // - cause item to move into "sent" folder
+ FOLDER = "sent";
+ if (!SESSIONVAR("retransfer_body")) {
+ // - prevent body retransfer, but not for dumb P800/P900/M600/P990 clients
+ BODY = UNASSIGNED; // prevent body transfer
+ ATT_COUNT = 0; // prevent attachment transfer
+ ATT_CONTENTS = UNASSIGNED;
+ // basically, this item is not limited (already complete on the client)
+ // even if contents are not sent
+ LIMIT = -1;
+ SETSIZELIMIT(-1);
+ }
+ }
+ else {
+ // outgoing item to any folder of of remote (inbox, sent...)
+ // - limit body to what is set in the LIMIT field
+ // %%% probably obsolete, as textitem will handle limit field automatically for >=V1.0.8.21
+ IF (LIMIT==EMPTY)
+ LIMIT = SIZELIMIT(); // if none set already, use default for this item (=default of datastore, if not SETSIZELIMIT() called before for this item generation)
+ }
+ // set limit for item generator
+ if (LIMIT!=EMPTY)
+ SETSIZELIMIT(LIMIT);
+ ]]></macro>
+
+
+ <macro name="EMAIL_FILTERINIT_SCRIPT"><![CDATA[
+ // check if we need to filter
+ INTEGER NEEDFILTER;
+
+ NEEDFILTER =
+ !DBHANDLESOPTS() && // only if DB cannot handle it
+ (STARTDATE()!=EMPTY); // and only if a start date is set (end date not needed as there are never future emails today)
+ SETFILTERALL(NEEDFILTER);
+ RETURN NEEDFILTER;
+ ]]></macro>
+
+
+ <macro name="EMAIL_FILTER_SCRIPT"><![CDATA[
+ INTEGER PASSES;
+
+ // check if item passes filter
+ PASSES=FALSE;
+ // Emails pass if they have a MAILDATE on or later than start date
+ PASSES = MAILDATE>=STARTDATE();
+ RETURN PASSES;
+ ]]></macro>
--- /dev/null
+<?xml version="1.0"?>
+<!-- SYNTHESIS SYNCML CLIENT Version 3.2 Configuration file -->
+
+<sysync_config version="1.0">
+
+ <configvar name="logpath" value="$(defout_path)"/>
+
+ <!-- this string is output to every session debug logfile to identify the config in use -->
+ <configidstring>SyncEvolution client config</configidstring>
+
+ <!-- information about maximum supported message and object size (in bytes) -->
+ <maxmsgsize/>
+ <maxobjsize/>
+
+ <!-- information for DevInf -->
+ <model/>
+ <manufacturer/>
+ <hardwareversion/>
+ <firmwareversion/>
+ <devicetype/>
+ <configdate/>
+
+ <debug/>
+
+ <transport type="xpt">
+ <!-- allow HTTP 1.1 kepp-alive (multiple request-answer-exchanges in single TCP connection) -->
+ <keepconnection>true</keepconnection>
+ </transport>
+
+ <scripting/>
+
+ <datatypes/>
+
+ <clientorserver/>
+</sysync_config>
--- /dev/null
+#! /usr/bin/env perl
+
+sub basename {
+ $_ = shift;
+ s;.*/;;;
+ return $_;
+}
+
+# Concatenate all files ending in .xml in the given directory
+# plus those in a specific subdirectory for client or server.
+# Order lexicographic ascending of the base filename.
+
+sub readfragments {
+ my $dir = shift;
+ my $subdir = shift;
+ my @res = ();
+
+ my @files = ();
+ if (opendir(my $dh, $dir)) {
+ foreach (grep (/.*\.xml$/, readdir($dh))) {
+ push @files, "$dir/$_";
+ }
+ closedir($dh);
+
+ if (opendir(my $dh, "$dir/$subdir")) {
+ foreach (grep (/.*\.xml$/, readdir($dh))) {
+ push @files, "$dir/$subdir/$_";
+ }
+ closedir($dh);
+ }
+ }
+
+ @files = sort { basename($a) <=> basename($b) } @files;
+ foreach (@files) {
+ open(IN, "<$_") || die "cannot read $_: $!";
+ push @res, <IN>;
+ close(IN);
+ }
+
+ return join("", @res);
+}
+
+# replace content of <debug>, <scripting>, <datatypes> and all <remoterule>s
+# with the corresponding shared and/or client/server .xml fragments
+sub update {
+ my $file = shift;
+ my $subdir = shift;
+ my $write = shift;
+
+ open(IN, "<$file") || die "cannot read $file: $!";
+ $_ = join("", <IN>);
+ close(IN) || die "closing $file: $!";
+
+ s;(<debug>\n).*(\n *</debug>);$1 . readfragments("debug", $subdir) . $2;se;
+ s;(<scripting>\n).*(\n *</scripting>);$1 . readfragments("scripting", $subdir) . $2;se ||
+ s;(\n *)<scripting/>;$1 . "<scripting>\n" . readfragments("scripting", $subdir) . $1 . "</scripting>";se;
+ s;(<datatypes>\n).*(\n *</datatypes>);$1 . readfragments("datatypes", $subdir) . $2;se ||
+ s;(\n *)<datatypes/>;$1 . "<datatypes>\n" . readfragments("datatypes", $subdir) . $1 . "</datatypes>";se;
+ s;(\n *)<remoterule>.*</remoterule>;$1 . readfragments("remoterules", $subdir);se ||
+ s;(\n *)<remoterules/>;readfragments("remoterules", $subdir);se;
+
+ if ($write) {
+ open(OUT, ">$file") || die "cannot write $file: $!";
+ print OUT;
+ close(OUT) || die "closing $file: $!";
+ } else {
+ print;
+ }
+}
+
+if ($#ARGV == -1) {
+ update("syncclient_sample_config.xml", "client", 1);
+ update("syncserv_sample_config.xml", "server", 1);
+} else {
+ update($ARGV[0], $ARGV[1], 0);
+}
}
int EDSAbiHaveEbook, EDSAbiHaveEcal, EDSAbiHaveEdataserver;
+int SyncEvoHaveLibbluetooth;
#ifdef EVOLUTION_COMPATIBILITY
namespace {
+enum {
+ FIND_SYMBOLS_NEED_ALL = 1<<0, /**< all symbols must be present for findSymbols() to succeed */
+ FIND_SYMBOLS_LENIENT_MAX_VERSION = 1<<1 /**< also allow libs with higher version, with extra warning */
+};
+
+
/**
* Opens a <basename>.<num> shared object with <num> coming from a
* range of known compatible versions, falling back to even more
* @param libname full name including .so suffix; .<num> gets appended
* @param minver first known compatible version
* @param maxver last known compatible version
+ * @param flags controls specific features
+ * @retval realver found version
* @return dlhandle which must be kept or freed by caller
*/
-void *findSymbols(const char *libname, int minver, int maxver, ... /* function pointer address, name, ..., (void *)0 */)
+void *findSymbols(const char *libname, int minver, int maxver,
+ int flags, int *realver, ... /* function pointer address, name, ..., (void *)0 */)
{
void *dlhandle = NULL;
std::ostringstream debug, info;
+ int ver;
if (!dlhandle) {
- for (int ver = maxver;
+ for (ver = maxver;
ver >= minver;
--ver) {
std::ostringstream soname;
}
}
- if (!dlhandle) {
- for (int ver = maxver + 1;
+ if (!dlhandle && (flags & FIND_SYMBOLS_LENIENT_MAX_VERSION)) {
+ for (ver = maxver + 1;
ver < maxver + 50;
++ver) {
std::ostringstream soname;
}
}
}
-
+
+ if (realver) {
+ *realver = ver;
+ }
+
if (!dlhandle) {
debug << libname << " not found (tried major versions " << minver << " to " << maxver + 49 << ")" << std::endl;
} else {
bool allfound = true;
va_list ap;
- va_start(ap, maxver);
+ va_start(ap, realver);
void **funcptr = va_arg(ap, void **);
const char *symname = NULL;
while (funcptr && allfound) {
}
va_end(ap);
- if (!allfound) {
+ if (!allfound && (flags & FIND_SYMBOLS_NEED_ALL)) {
/* unusable, clear symbols and free handle */
- va_start(ap, maxver);
+ va_start(ap, realver);
funcptr = va_arg(ap, void **);
while (funcptr) {
va_arg(ap, const char *);
# ifdef ENABLE_ECAL
void *ecalhandle;
# endif
+# ifdef ENABLE_BLUETOOTH
+ void *libbluetoothhandle;
+ sdp_record_t *wrap_sdp_extract_pdu(const uint8_t *pdata, int bufsize, int *scanned) { return EDSAbiWrapperSingleton.sdp_extract_pdu(pdata, scanned); }
+ int wrap_sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size) { return EDSAbiWrapperSingleton.sdp_extract_seqtype(buf, dtdp, size); }
+# endif
}
#endif // EVOLUTION_COMPATIBILITY
extern "C" int EDSAbiHaveEbook, EDSAbiHaveEcal, EDSAbiHaveEdataserver;
+extern "C" int SyncEvoHaveLibbluetooth;
extern "C" void EDSAbiWrapperInit()
{
# ifdef HAVE_EDS
edshandle =
findSymbols("libedataserver-1.2.so", 7, 11,
+ FIND_SYMBOLS_NEED_ALL|FIND_SYMBOLS_LENIENT_MAX_VERSION, NULL,
&EDSAbiWrapperSingleton.e_source_get_type, "e_source_get_type",
&EDSAbiWrapperSingleton.e_source_get_uri, "e_source_get_uri",
&EDSAbiWrapperSingleton.e_source_group_get_type, "e_source_group_get_type",
# ifdef ENABLE_EBOOK
ebookhandle =
findSymbols("libebook-1.2.so", 5, 9,
+ FIND_SYMBOLS_NEED_ALL|FIND_SYMBOLS_LENIENT_MAX_VERSION, NULL,
&EDSAbiWrapperSingleton.e_book_add_contact, "e_book_add_contact",
&EDSAbiWrapperSingleton.e_book_authenticate_user, "e_book_authenticate_user",
&EDSAbiWrapperSingleton.e_book_commit_contact, "e_book_commit_contact",
# ifdef ENABLE_ECAL
ecalhandle =
findSymbols("libecal-1.2.so", 3, 7,
+ FIND_SYMBOLS_NEED_ALL|FIND_SYMBOLS_LENIENT_MAX_VERSION, NULL,
&EDSAbiWrapperSingleton.e_cal_add_timezone, "e_cal_add_timezone",
&EDSAbiWrapperSingleton.e_cal_component_get_icalcomponent, "e_cal_component_get_icalcomponent",
&EDSAbiWrapperSingleton.e_cal_component_get_last_modified, "e_cal_component_get_last_modified",
&EDSAbiWrapperSingleton.icaltimezone_set_component, "icaltimezone_set_component",
(void *)0);
EDSAbiHaveEcal = EDSAbiWrapperSingleton.e_cal_new != 0;
+ ecalhandle =
+ findSymbols("libecal-1.2.so", 3, 7,
+ FIND_SYMBOLS_LENIENT_MAX_VERSION, NULL,
+ &EDSAbiWrapperSingleton.icalcomponent_as_ical_string_r, "icalcomponent_as_ical_string_r",
+ &EDSAbiWrapperSingleton.icaltime_as_ical_string_r, "icaltime_as_ical_string_r",
+ (void *)0);
# endif // ENABLE_ECAL
+
+# ifdef ENABLE_BLUETOOTH
+ int bluetooth_version;
+ libbluetoothhandle =
+ findSymbols("libbluetooth.so", 2, 3, 0, &bluetooth_version,
+ &EDSAbiWrapperSingleton.sdp_close, "sdp_close",
+ &EDSAbiWrapperSingleton.sdp_connect, "sdp_connect",
+ &EDSAbiWrapperSingleton.sdp_extract_pdu, "sdp_extract_pdu",
+ &EDSAbiWrapperSingleton.sdp_extract_pdu_safe, "sdp_extract_pdu_safe",
+ &EDSAbiWrapperSingleton.sdp_extract_seqtype, "sdp_extract_seqtype",
+ &EDSAbiWrapperSingleton.sdp_extract_seqtype_safe, "sdp_extract_seqtype_safe",
+ &EDSAbiWrapperSingleton.sdp_get_access_protos, "sdp_get_access_protos",
+ &EDSAbiWrapperSingleton.sdp_get_proto_port, "sdp_get_proto_port",
+ &EDSAbiWrapperSingleton.sdp_get_socket, "sdp_get_socket",
+ &EDSAbiWrapperSingleton.sdp_list_append, "sdp_list_append",
+ &EDSAbiWrapperSingleton.sdp_list_free, "sdp_list_free",
+ &EDSAbiWrapperSingleton.sdp_process, "sdp_process",
+ &EDSAbiWrapperSingleton.sdp_record_free, "sdp_record_free",
+ &EDSAbiWrapperSingleton.sdp_service_search_attr_async, "sdp_service_search_attr_async",
+ &EDSAbiWrapperSingleton.sdp_set_notify, "sdp_set_notify",
+ &EDSAbiWrapperSingleton.sdp_uuid128_create, "sdp_uuid128_create",
+ &EDSAbiWrapperSingleton.str2ba, "str2ba",
+ (void *)0);
+ if (bluetooth_version == 2) {
+ // libbluetooth.so.2's sdp_extract_pdu() and
+ // sdp_extract_seqtype() do not match our prototype (have no
+ // bufsize). Some versions have a _safe variant. If not, use
+ // wrappers which accept the bufsize parameter and drop it.
+ if (!EDSAbiWrapperSingleton.sdp_extract_pdu_safe) {
+ EDSAbiWrapperSingleton.sdp_extract_pdu_safe = wrap_sdp_extract_pdu;
+ }
+ if (!EDSAbiWrapperSingleton.sdp_extract_seqtype_safe) {
+ EDSAbiWrapperSingleton.sdp_extract_seqtype_safe = wrap_sdp_extract_seqtype;
+ }
+ } else {
+ // _safe variants were removed in favor of an API/ABI change. Redirect
+ // into normal versions. We know they have the right prototype because
+ // of that change.
+ EDSAbiWrapperSingleton.sdp_extract_pdu_safe = reinterpret_cast<typeof(EDSAbiWrapperSingleton.sdp_extract_pdu_safe)>(EDSAbiWrapperSingleton.sdp_extract_pdu);
+ EDSAbiWrapperSingleton.sdp_extract_seqtype_safe = reinterpret_cast<typeof(EDSAbiWrapperSingleton.sdp_extract_seqtype_safe)>(EDSAbiWrapperSingleton.sdp_extract_seqtype);
+ }
+ SyncEvoHaveLibbluetooth = EDSAbiWrapperSingleton.sdp_connect != 0;
+# endif
#else // EVOLUTION_COMPATIBILITY
# ifdef HAVE_EDS
EDSAbiHaveEdataserver = true;
# ifdef ENABLE_ECAL
EDSAbiHaveEcal = true;
# endif
+# ifdef ENABLE_BLUETOOTH
+ SyncEvoHaveLibbluetooth = true;
+# endif
#endif // EVOLUTION_COMPATIBILITY
}
*/
/**
- * The purpose of this file is to separate SyncEvolution from
+ * The main purpose of this file is to separate SyncEvolution from
* Evolution Dataserver ABI changes by never depending directly
* on any symbol in its libraries. Instead all functions are
* called via function pointers found via dlopen/dlsym.
* may fail when the functions needed by SyncEvolution change.
*
* History shows that this has not happened for a long time whereas
- * the version of libs had to be bumped quite a few times due to other
+ * the versions of EDS libs had to be bumped quite a few times due to other
* changes.
*
+ * A similar problem came up with an API and ABI change in
+ * libbluetooth.so.3: the sdp_extract_seqtype() and sdp_extract_pdu()
+ * gained one more parameter (a buffer size for the buffer being
+ * written into). When compatibility mode is enabled, this header
+ * file provides the extended version and maps it back to the older
+ * version if necessary.
+ *
* To use the wrappers, include this header file. It overrides
* the normal C API functions with the function pointers via
* defines.
#include <libecal/e-cal.h>
#endif
#endif
+#ifdef ENABLE_BLUETOOTH
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+#endif
#ifdef __cplusplus
extern "C" {
/** libebook, libecal, libedataserver available (currently checks for e_book_new/e_cal_new/e_source_group_peek_sources) */
extern int EDSAbiHaveEbook, EDSAbiHaveEcal, EDSAbiHaveEdataserver;
+/** libbluetooth available (checks sdp_connect()) */
+extern int SyncEvoHaveLibbluetooth;
+
#ifdef EVOLUTION_COMPATIBILITY
/**
char* (*icaltimezone_get_tzid) (icaltimezone *zone);
icaltimezone *(*icaltimezone_new) (void);
int (*icaltimezone_set_component) (icaltimezone *zone, icalcomponent *comp);
+
+ // optional variants which allocate the returned string for us
+ const char* (*icaltime_as_ical_string_r) (const struct icaltimetype tt);
+ char* (*icalcomponent_as_ical_string_r) (icalcomponent* component);
# endif /* ENABLE_ECAL */
+# ifdef ENABLE_BLUETOOTH
+ int (*sdp_close)(sdp_session_t *session);
+ sdp_session_t *(*sdp_connect)(const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags);
+ /** libbluetooth.so.2 version of sdp_extract_pdu() */
+ sdp_record_t *(*sdp_extract_pdu)(const uint8_t *pdata, int *scanned);
+ /** alternate version of sdp_extract_pdu() only found in some releases of libbluetooth.so.2 */
+ sdp_record_t *(*sdp_extract_pdu_safe)(const uint8_t *pdata, int bufsize, int *scanned);
+ /** libbluetooth.so.2 version of sdp_extract_seqtype() */
+ int (*sdp_extract_seqtype)(const uint8_t *buf, uint8_t *dtdp, int *size);
+ /** alternate version of sdp_extract_seqtype() only found in some releases of libbluetooth.so.2 */
+ int (*sdp_extract_seqtype_safe)(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size);
+ int (*sdp_get_access_protos)(const sdp_record_t *rec, sdp_list_t **protos);
+ int (*sdp_get_proto_port)(const sdp_list_t *list, int proto);
+ int (*sdp_get_socket)(const sdp_session_t *session);
+ sdp_list_t *(*sdp_list_append)(sdp_list_t *list, void *d);
+ void (*sdp_list_free)(sdp_list_t *list, sdp_free_func_t f);
+ int (*sdp_process)(sdp_session_t *session);
+ void (*sdp_record_free)(sdp_record_t *rec);
+ int (*sdp_service_search_attr_async)(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
+ int (*sdp_set_notify)(sdp_session_t *session, sdp_callback_t *func, void *udata);
+ uuid_t *(*sdp_uuid128_create)(uuid_t *uuid, const void *data);
+ int (*str2ba)(const char *str, bdaddr_t *ba);
+# endif /* ENABLE_BLUETOOTH */
+
int initialized;
};
# define e_cal_remove_object_with_mod EDSAbiWrapperSingleton.e_cal_remove_object_with_mod
# define e_cal_set_auth_func EDSAbiWrapperSingleton.e_cal_set_auth_func
# define icalcomponent_add_component EDSAbiWrapperSingleton.icalcomponent_add_component
-# define icalcomponent_as_ical_string EDSAbiWrapperSingleton.icalcomponent_as_ical_string
+# define icalcomponent_as_ical_string (EDSAbiWrapperSingleton.icalcomponent_as_ical_string_r ? EDSAbiWrapperSingleton.icalcomponent_as_ical_string_r : EDSAbiWrapperSingleton.icalcomponent_as_ical_string)
# define icalcomponent_free EDSAbiWrapperSingleton.icalcomponent_free
# define icalcomponent_get_first_component EDSAbiWrapperSingleton.icalcomponent_get_first_component
# define icalcomponent_get_first_property EDSAbiWrapperSingleton.icalcomponent_get_first_property
# define icalproperty_new_summary EDSAbiWrapperSingleton.icalproperty_new_summary
# define icalproperty_set_value_from_string EDSAbiWrapperSingleton.icalproperty_set_value_from_string
# define icalproperty_remove_parameter_by_kind EDSAbiWrapperSingleton.icalproperty_remove_parameter_by_kind
-# define icaltime_as_ical_string EDSAbiWrapperSingleton.icaltime_as_ical_string
+# define icaltime_as_ical_string (EDSAbiWrapperSingleton.icaltime_as_ical_string_r ? EDSAbiWrapperSingleton.icaltime_as_ical_string_r : EDSAbiWrapperSingleton.icaltime_as_ical_string)
# define icaltimezone_free EDSAbiWrapperSingleton.icaltimezone_free
# define icaltimezone_get_builtin_timezone EDSAbiWrapperSingleton.icaltimezone_get_builtin_timezone
# define icaltimezone_get_builtin_timezone_from_tzid EDSAbiWrapperSingleton.icaltimezone_get_builtin_timezone_from_tzid
# define icaltimezone_new EDSAbiWrapperSingleton.icaltimezone_new
# define icaltimezone_set_component EDSAbiWrapperSingleton.icaltimezone_set_component
# endif /* ENABLE_ECAL */
+# ifdef ENABLE_BLUETOOTH
+# define sdp_close EDSAbiWrapperSingleton.sdp_close
+# define sdp_connect EDSAbiWrapperSingleton.sdp_connect
+# define sdp_extract_pdu do_not_use_sdp_extract_pdu
+# define sdp_extract_pdu_safe EDSAbiWrapperSingleton.sdp_extract_pdu_safe
+# define sdp_extract_seqtype do_not_use_sdp_extract_seqtype
+# define sdp_extract_seqtype_safe EDSAbiWrapperSingleton.sdp_extract_seqtype_safe
+# define sdp_get_access_protos EDSAbiWrapperSingleton.sdp_get_access_protos
+# define sdp_get_proto_port EDSAbiWrapperSingleton.sdp_get_proto_port
+# define sdp_get_socket EDSAbiWrapperSingleton.sdp_get_socket
+# define sdp_list_append EDSAbiWrapperSingleton.sdp_list_append
+# define sdp_list_free EDSAbiWrapperSingleton.sdp_list_free
+# define sdp_process EDSAbiWrapperSingleton.sdp_process
+# define sdp_record_free EDSAbiWrapperSingleton.sdp_record_free
+# define sdp_service_search_attr_async EDSAbiWrapperSingleton.sdp_service_search_attr_async
+# define sdp_set_notify EDSAbiWrapperSingleton.sdp_set_notify
+# define sdp_uuid128_create EDSAbiWrapperSingleton.sdp_uuid128_create
+# define str2ba EDSAbiWrapperSingleton.str2ba
+# endif /* ENABLE_BLUETOOTH */
# endif /* EDS_ABI_WRAPPER_NO_REDEFINE */
+#else /* EVOLUTION_COMPATIBILITY */
+
+# if !defined(EDS_ABI_WRAPPER_NO_REDEFINE) && defined(HAVE_LIBICAL_R)
+# ifdef ENABLE_ECAL
+# ifndef LIBICAL_MEMFIXES
+ /* This changes the semantic of the normal functions the same way as libecal did. */
+# define LIBICAL_MEMFIXES 1
+# define icaltime_as_ical_string icaltime_as_ical_string_r
+# define icalcomponent_as_ical_string icalcomponent_as_ical_string_r
+# endif /* LIBICAL_MEMFIXES */
+# endif /* ENABLE_ECAL */
+# endif /* EDS_ABI_WRAPPER_NO_REDEFINE */
#endif /* EVOLUTION_COMPATIBILITY */
/** initialize pointers to EDS functions, if necessary; can be called multiple times */
#include <sys/types.h>
#include <dirent.h>
+#if USE_SHA256 == 1
+# include <glib.h>
+#elif USE_SHA256 == 2
+# include <nss/sechash.h>
+# include <nss/hasht.h>
+# include <nss.h>
+#endif
+
#ifdef ENABLE_UNIT_TESTS
#include "test.h"
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("SyncEvolution");
return hashval;
}
+unsigned long Hash(const std::string &str)
+{
+ unsigned long hashval = 5381;
+
+ BOOST_FOREACH(int c, str) {
+ hashval = ((hashval << 5) + hashval) + c;
+ }
+
+ return hashval;
+}
+
+std::string SHA_256(const std::string &data)
+{
+#if USE_SHA256 == 1
+ GString hash(g_compute_checksum_for_data(G_CHECKSUM_SHA256, (guchar *)data.c_str(), data.size()),
+ "g_compute_checksum_for_data() failed");
+ return std::string(hash.get());
+#elif USE_SHA256 == 2
+ std::string res;
+ unsigned char hash[SHA256_LENGTH];
+ static bool initialized;
+ if (!initialized) {
+ // https://wiki.mozilla.org/NSS_Shared_DB_And_LINUX has
+ // some comments which indicate that calling init multiple
+ // times works, but http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslfnc.html#1234224
+ // says it must only be called once. How that is supposed
+ // to work when multiple, independent libraries have to
+ // use NSS is beyond me. Bad design. At least let's do the
+ // best we can here.
+ NSS_NoDB_Init(NULL);
+ initialized = true;
+ }
+
+ if (HASH_HashBuf(HASH_AlgSHA256, hash, (unsigned char *)data.c_str(), data.size()) != SECSuccess) {
+ SE_THROW("NSS HASH_HashBuf() failed");
+ }
+ res.reserve(SHA256_LENGTH * 2);
+ BOOST_FOREACH(unsigned char value, hash) {
+ res += StringPrintf("%02x", value);
+ }
+ return res;
+#else
+ SE_THROW("Hash256() not implemented");
+ return "";
+#endif
+}
+
+
std::string StringPrintf(const char *format, ...)
{
va_list ap;
return splitStrings;
}
+ScopedEnvChange::ScopedEnvChange(const string &var, const string &value) :
+ m_var(var)
+{
+ const char *oldval = getenv(var.c_str());
+ if (oldval) {
+ m_oldvalset = true;
+ m_oldval = oldval;
+ } else {
+ m_oldvalset = false;
+ }
+ setenv(var.c_str(), value.c_str(), 1);
+}
+
+ScopedEnvChange::~ScopedEnvChange()
+{
+ if (m_oldvalset) {
+ setenv(m_var.c_str(), m_oldval.c_str(), 1);
+ } else {
+ unsetenv(m_var.c_str());
+ }
+}
SE_END_CXX
* Simple string hash function, derived from Dan Bernstein's algorithm.
*/
unsigned long Hash(const char *str);
+unsigned long Hash(const std::string &str);
+
+/**
+ * SHA-256 implementation, returning hash as lowercase hex string (like sha256sum).
+ * Might not be available, in which case it raises an exception.
+ */
+std::string SHA_256(const std::string &in);
/**
* This is a simplified implementation of a class representing and calculating
* */
std::vector<std::string> unescapeJoinedString (const std::string &src, char separator);
+/**
+ * Temporarily set env variable, restore old value on destruction.
+ * Useful for unit tests which depend on the environment.
+ */
+class ScopedEnvChange
+{
+ public:
+ ScopedEnvChange(const string &var, const string &value);
+ ~ScopedEnvChange();
+ private:
+ string m_var, m_oldval;
+ bool m_oldvalset;
+};
+
/** throw a normal SyncEvolution Exception, including source information */
#define SE_THROW(_what) \
SE_THROW_EXCEPTION(Exception, _what)
# Generated by configure. Do no edit.
-# git revision 29763216a67787705ecdce113701a17542ab2721
-# git tag libsynthesis_3.2.0.35+syncevolution-0-9-1-beta1-150-g2976321
+# git revision 904d1fb47ecd39c58f349012fd4c343d6fcf63e9
+# git tag libsynthesis_3.4.0.5+syncevolution-1-0-beta-2
+
+2010-02-23 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/Makefile.am.in:
+
+ .so version bumped to 0.3.1 (minor revision increased)
+
+2010-02-18 Lukas Zeller <luz@synthesis.ch>
+
+
+ Merge remote branch 'moblin/master' into luz
+
+2010-02-18 Lukas Zeller <luz@synthesis.ch>
+
+ * src/global_options.h:
+ * src/sysync/binfileimplclient.cpp:
+ * src/sysync/customimplds.h:
+ * src/sysync/localengineds.cpp:
+ * src/sysync/localengineds.h:
+ * src/sysync/stdlogicds.h:
+ * src/sysync/superdatastore.cpp:
+ * src/sysync/superdatastore.h:
+ * src/sysync/syncagent.cpp:
+
+ Engine 3.4.0.5: implemented client-side superdatastores according
+ to suggestion/draft implementation of Patrick
+
+2010-02-18 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/syncsession.cpp:
+
+ engine: now shows engine-determined OS/version as well as
+ configured hwv/fwv in log
+
+2010-02-16 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/syncappbase.cpp:
+
+ engine: added more configurable devInf data via config variables
+
+2010-02-13 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/syncagent.cpp:
+ * src/sysync/syncappbase.cpp:
+ * src/sysync/syncappbase.h:
+ * src/sysync/syncsession.cpp:
+
+ engine: added configurable device ID (via "customdeviceid" config
+ variable)
+
+2010-02-11 Chen Congwu <congwu.chen@intel.com>
+
+ * src/syncml_tk/src/sml/lib/all/libstr.c:
+ * src/syncml_tk/src/sml/lib/inc/libstr.h:
+ * src/syncml_tk/src/sml/xlt/all/xltdecxml.c:
+ * src/syncml_tk/src/sml/xlt/all/xlttags.c:
+
+ xmltk fixes for Nokia ovi service
+
+2010-02-09 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/sysync_SDK/Sources/enginemodulebase.cpp:
+
+ TEngineModuleBase::Connect() - fixed compiler warning
+
+2010-02-09 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/sysync/synccommand.cpp:
+
+ do not treat 418 = "item exists" as an error
+
+2010-02-04 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/sysync/syncagent.cpp:
+ * src/sysync_SDK/Sources/syerror.h:
+
+ LOCERR_DATASTORE_ABORT: abort store, not session
+
+2010-02-05 Lukas Zeller <luz@synthesis.ch>
+
+ * src/global_options.h:
+ * src/sysync/localengineds.cpp:
+ * src/sysync/mimedirprofile.cpp:
+ * src/sysync/mimedirprofile.h:
+ * src/sysync/scriptcontext.cpp:
+ * src/sysync/syncsession.cpp:
+ * src/sysync/syncsession.h:
+
+ Engine 3.4.0.4: enhanced remote rules with subrules and multiple
+ active rules per session
+
+2010-02-05 Lukas Zeller <luz@synthesis.ch>
+
+
+ Merge remote branch 'moblin/master' into luz
+
+2010-02-03 Lukas Zeller <luz@synthesis.ch>
+
+ * src/Targets/clientEngine_dbg/target_options.h:
+
+ target_options for basic DBG engine: cosmetic cleanup, not
+ relevant for normal libsynthesis builds
+
+2010-02-03 Beat Forster <bfo@synthesis.ch>
+
+ * src/platform_adapters/linux/configfiles.cpp:
+
+ Android: configfiles: avoid double slash in path name
+
+2010-02-03 Beat Forster <bfo@synthesis.ch>
+
+ * src/sysync_SDK/Sources/SDK_util.c:
+
+ SDK_util.c : cosmetic - renamed define
+
+2010-02-03 Beat Forster <bfo@synthesis.ch>
+
+ * src/sysync_SDK/Sources/sync_dbapidef.h:
+
+ sync_dbapidef.h:
+
+2010-02-01 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/sysync_SDK/configs/README:
+ * src/sysync_SDK/configs/datatypes/00vcard-fieldlist.xml:
+ * src/sysync_SDK/configs/datatypes/01vcard-profile.xml:
+ * src/sysync_SDK/configs/datatypes/02vcard-types.xml:
+ * src/sysync_SDK/configs/datatypes/10calendar-fieldlist.xml:
+ * src/sysync_SDK/configs/datatypes/11calendar-profile.xml:
+ * src/sysync_SDK/configs/datatypes/12calendar-types.xml:
+ * src/sysync_SDK/configs/datatypes/20note-fieldlist.xml:
+ * src/sysync_SDK/configs/datatypes/21note-profile.xml:
+ * src/sysync_SDK/configs/datatypes/22notes-types.xml:
+ * src/sysync_SDK/configs/datatypes/30bookmark-fieldlist.xml:
+ * src/sysync_SDK/configs/datatypes/31bookmark-profile.xml:
+ * src/sysync_SDK/configs/datatypes/32bookmark-type.xml:
+ * src/sysync_SDK/configs/datatypes/server/40email-fieldlist.xml:
+ * src/sysync_SDK/configs/datatypes/server/41email-profile.xml:
+ * src/sysync_SDK/configs/datatypes/server/42email-type-zipped.xml:
+ * src/sysync_SDK/configs/datatypes/server/42email-type.xml:
+ * src/sysync_SDK/configs/datatypes/server/43email-sonyericsson.xml:
+ * src/sysync_SDK/configs/datatypes/server/44email-nokia9500.xml:
+ * src/sysync_SDK/configs/debug/00default.xml:
+ * src/sysync_SDK/configs/remoterules/server/00_t39m.xml:
+ * src/sysync_SDK/configs/remoterules/server/01_t68.xml:
+ * src/sysync_SDK/configs/remoterules/server/02_V3.xml:
+ * src/sysync_SDK/configs/remoterules/server/03_V3i.xml:
+ * src/sysync_SDK/configs/remoterules/server/04_6230.xml:
+ * src/sysync_SDK/configs/remoterules/server/05_9210.xml:
+ * src/sysync_SDK/configs/remoterules/server/06_9210i.xml:
+ * src/sysync_SDK/configs/remoterules/server/07_3220.xml:
+ * src/sysync_SDK/configs/remoterules/server/08_3230.xml:
+ * src/sysync_SDK/configs/remoterules/server/09_3600.xml:
+ * src/sysync_SDK/configs/remoterules/server/10_3620.xml:
+ * src/sysync_SDK/configs/remoterules/server/11_3650.xml:
+ * src/sysync_SDK/configs/remoterules/server/12_3660.xml:
+ * src/sysync_SDK/configs/remoterules/server/13_6260.xml:
+ * src/sysync_SDK/configs/remoterules/server/14_6600.xml:
+ * src/sysync_SDK/configs/remoterules/server/15_6620.xml:
+ * src/sysync_SDK/configs/remoterules/server/16_6630.xml:
+ * src/sysync_SDK/configs/remoterules/server/17_6670.xml:
+ * src/sysync_SDK/configs/remoterules/server/18_7250.xml:
+ * src/sysync_SDK/configs/remoterules/server/19_7250i.xml:
+ * src/sysync_SDK/configs/remoterules/server/20_7260.xml:
+ * src/sysync_SDK/configs/remoterules/server/21_7610.xml:
+ * src/sysync_SDK/configs/remoterules/server/22_7650.xml:
+ * src/sysync_SDK/configs/remoterules/server/23_N-Gage.xml:
+ * src/sysync_SDK/configs/remoterules/server/24_N-Gage_QD.xml:
+ * src/sysync_SDK/configs/remoterules/server/25_9300.xml:
+ * src/sysync_SDK/configs/remoterules/server/26_9500.xml:
+ * src/sysync_SDK/configs/remoterules/server/27_E90.xml:
+ * src/sysync_SDK/configs/remoterules/server/28_X.xml:
+ * src/sysync_SDK/configs/remoterules/server/29_SX1.xml:
+ * src/sysync_SDK/configs/remoterules/server/30_M55.xml:
+ * src/sysync_SDK/configs/remoterules/server/31_SL55.xml:
+ * src/sysync_SDK/configs/remoterules/server/32_S55.xml:
+ * src/sysync_SDK/configs/remoterules/server/33_S65.xml:
+ * src/sysync_SDK/configs/remoterules/server/34_SL65.xml:
+ * src/sysync_SDK/configs/remoterules/server/35_K700.xml:
+ * src/sysync_SDK/configs/remoterules/server/36_T610_T630.xml:
+ * src/sysync_SDK/configs/remoterules/server/37_M600i.xml:
+ * src/sysync_SDK/configs/remoterules/server/38_P800.xml:
+ * src/sysync_SDK/configs/remoterules/server/39_P900.xml:
+ * src/sysync_SDK/configs/remoterules/server/40_P910.xml:
+ * src/sysync_SDK/configs/remoterules/server/41_P910i.xml:
+ * src/sysync_SDK/configs/remoterules/server/42_P990i.xml:
+ * src/sysync_SDK/configs/remoterules/server/43_t68i.xml:
+ * src/sysync_SDK/configs/remoterules/server/44_Funambol_Outlook.xml:
+ * src/sysync_SDK/configs/remoterules/server/45_SyncJe_Outlook.xml:
+ * src/sysync_SDK/configs/scripting/10newuid.xml:
+ * src/sysync_SDK/configs/scripting/11calendar.xml:
+ * src/sysync_SDK/configs/scripting/client/00timeout.xml:
+ * src/sysync_SDK/configs/scripting/server/12email.xml:
+ * src/sysync_SDK/configs/syncclient_sample_config.xml:
+ * src/sysync_SDK/configs/syncserv_sample_config.xml:
+ * src/sysync_SDK/configs/update-samples.pl:
+
+ XML config samples: split up into individual fragments
+
+2010-02-02 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/stdlogicds.cpp:
+
+ Added check such that if <datastoreinitscript> calls
+ ABORTDATASTORE(), the abort gets propagated
+
+2010-02-01 Patrick Ohly <patrick.ohly@intel.com>
+
+ * src/sysync_SDK/configs/syncserv_sample_config.xml:
+
+ syncserv_sample_config.xml: removed <CA> white space
+
+2010-01-28 BeatForster <elisabethegli@bfo-MacBookPro.local>
+
+ * src/sysync/tz_table.h:
+
+ tz_table.h: Argentina changed to America/Buenos_Aires
+
+2010-01-25 BeatForster <elisabethegli@bfo-MacBookPro.local>
+
+ * src/sysync/tz_table.h:
+
+ ART/ARST timezone definitions for Buenos Aires, Argentina added
+
+2009-12-23 BeatForster <elisabethegli@bfo-MacBookPro.local>
+
+ * src/DB_interfaces/api_db/dbapi.cpp:
+ * src/DB_interfaces/api_db/dbapi.h:
+ * src/sysync_SDK/Sources/SDK_support.cpp:
+ * src/sysync_SDK/Sources/SDK_support.h:
+ * src/sysync_SDK/Sources/sync_dbapidef.h:
+
+ SDK: - create list of built-in plugins (plugin_info/logger) -
+ plugins can be accessed via #1..#X - break recursion at the
+ logger - dbapi: <fPlugin> added - Definition for CA_Plugin
+
+2009-12-23 BeatForster <elisabethegli@bfo-MacBookPro.local>
+
+ * src/sysync_SDK/Sources/SDK_util.c:
+ * src/sysync_SDK/Sources/sync_dbapidef.h:
+
+ SDK: - Version changed to V1.7.0 - at least callbackVersion=2
+ must be supported
+
+2009-12-20 BeatForster <elisabethegli@bfo-MacBookPro.local>
+
+ * src/client_engine_linux.mk:
+
+ Linux makefiles, several tabs/spaces replaced, did not work any
+ more like this
+
+2009-12-17 Beat Forster <elisabethegli@beat-forsters-macbook-pro.local>
+
+ * src/DB_interfaces/api_db/dbapi.cpp:
+ * src/DB_interfaces/api_db/dbapi_include.h:
+ * src/DB_interfaces/api_db/sync_dbapiconnect.cpp:
+ * src/sysync_SDK/Sources/sync_dbapidef.h:
+
+ DBAPi: Old variant of Module_PluginParams no longer supported
+
+2009-12-03 Beat Forster <elisabethegli@beat-forsters-macbook-pro.local>
+
+ * src/DB_interfaces/api_db/dbapi.cpp:
+ * src/DB_interfaces/api_db/dbapi.h:
+ * src/DB_interfaces/api_db/dbapi_include.h:
+ * src/DB_interfaces/api_db/sync_dbapiconnect.cpp:
+ * src/sysync_SDK/Sources/SDK_support.cpp:
+ * src/sysync_SDK/Sources/sync_dbapidef.h:
+
+ JNI/Java: Several bug fixes and enhancements - Preparing
+ com/sysync package for V1.6.2 - Old BLOB signature supported
+ until V1.6.1 - ModSubName() method added to TDB_Api_Config - both
+ syntax versions for package path supported - multiple connection
+ problems fixed - correct error for non-existing packages -
+ sysytest output layout adapted for packages
+
+2009-12-02 Beat Forster <elisabethegli@beat-forsters-macbook-pro.local>
+
+ * src/sysync/engineinterface.cpp:
+ * src/sysync_SDK/Sources/enginemodulebase.cpp:
+
+ SDK: enginemodulebase applies older callbackVersion correctly now
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * doc/SySync_script_call_flow.numbers/Contents/PkgInfo:
+ * doc/SySync_script_call_flow.numbers/QuickLook/Thumbnail.jpg:
+ * doc/SySync_script_call_flow.numbers/SySync diagram_plugin_small.jpg:
+ * doc/SySync_script_call_flow.numbers/document-thumbnail.tiff:
+ * doc/SySync_script_call_flow.numbers/index.xml.gz:
+ * doc/SySync_script_call_flow.pdf:
+
+ Doc: useful table showing the call flow of scripts within a
+ server session
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * src/global_options.h:
+
+ New Engine Version 3.4.0.3 started to show fact that moblin
+ patches are now included
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+
+ Merge remote branch 'moblin/master' into luz_tmp
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * src/global_options.h:
+ * src/sysync/localengineds.cpp:
+
+ Engine 3.4.0.2: fixed long standing bug parsing CGI filters with
+ paranthesized subexpressions
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/syncappbase.cpp:
+ * src/sysync/syserial.h:
+
+ NEVER_EXPIRES_IS_OK define is now required in target_options.h to
+ build targets without any licensing or expiry date
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/syncagent.cpp:
+ * src/sysync/syncsession.cpp:
+
+ bugfix for unilib regression: there must be no requestmaxtime
+ limit for clients!
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/rrules.cpp:
+
+ rrules: recurrence expansion bug with weekly recurrences fixed
+
+2010-01-27 Lukas Zeller <luz@synthesis.ch>
+
+ * src/sysync/debuglogger.cpp:
+
+ debuglogger: avoid the need to create an empty va_list (which is
+ not cleanly possible)
2010-01-18 Ove Kaaven <ovek@debian.org>
--- /dev/null
+????????
\ No newline at end of file
} // DisposeBlk
+// Returns true if <ps> is name or #<n>
+static bool BuiltIn( string &ps, int &n, cAppCharP name )
+{
+ if (strucmp( ps.c_str(), name )==0) return true;
+
+ string s= "#" + IntStr( n++ );
+ if (strucmp( ps.c_str(), s.c_str() )==0) { ps= name; return true; }
+
+ return false;
+} // BuiltIn
+
+
/* --- connect to library ------------------------------------------------- */
/*! These are the built-in linked libraries, which can be accessed directly
* The SDK concept allows to have some routines unimplemented,
* they will be provided by the "no_dbapi" built-in module.
*/
-static TSyError DBApi_LibAssign( appPointer aMod, cAppCharP aName, appPointer aField, int aFSize,
+static TSyError DBApi_LibAssign( appPointer aMod, string &ps, appPointer aField, int aFSize,
cAppCharP aKey= "" )
{
TSyError err= DB_NotFound;
-
- string p= Plugin_MainName( aName );
- p= NoBracks( p );
- cAppCharP ps= p.c_str();
+ int n= 0; // incremental counter starting with 0
// the blind adapter is always available and acts as default as well
- if (strucmp( ps,"" )==0 ||
- strucmp( ps,"no_dbapi" )==0) err= no_dbapi::AssignMethods( aMod, aField,aFSize, aKey );
+ if (strucmp( ps.c_str(), "" )==0 ||
+ BuiltIn( ps,n, "no_dbapi" )) err= no_dbapi::AssignMethods( aMod, aField,aFSize, aKey );
#ifdef DBAPI_DEMO // demo (C) adapter, which will be delivered with SDK
- else if (strucmp( ps,"SDK_demodb" )==0) err= SDK_demodb::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "SDK_demodb" )) err= SDK_demodb::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef DBAPI_EXAMPLE // other (C++) linked versions of the demo adapter (for test)
- else if (strucmp( ps,"example1" )==0) err= example1::AssignMethods( aMod, aField,aFSize, aKey );
- else if (strucmp( ps,"example2" )==0) err= example2::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "example1" )) err= example1::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "example2" )) err= example2::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef DBAPI_SILENT // a silent adapter, which always says, everthing is ok
- else if (strucmp( ps,"silent" )==0) err= silent::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "silent" )) err= silent::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef DBAPI_TEXT // "text_db" implementation, which emulates the "textdb"
- else if (strucmp( ps,"SDK_textdb" )==0) err= SDK_textdb::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "SDK_textdb" )) err= SDK_textdb::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef DBAPI_SNOWWHITE // "oceanblue/snowwhite" implementation
- else if (strucmp( ps,"snowwhite" )==0) err= oceanblue::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "snowwhite" )) err= oceanblue::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef PLUGIN_DLL // plugin bridges
#ifdef JNI_SUPPORT // the Java (JNI) adapter
- else if (strucmp( ps,"JNI" )==0) err= SDK_jni::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "JNI" )) err= SDK_jni::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef CSHARP_SUPPORT // the C# adapter
- else if (strucmp( ps,"CSHARP" )==0) err= SDK_csharp::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "CSHARP" )) err= SDK_csharp::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef DBAPI_TUNNEL // direct access to internal adapters
- else if (strucmp( ps,"tunnel" )==0) err= SDK_tunnel::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "tunnel" )) err= SDK_tunnel::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef DBAPI_LOGGER // dbapi logger bridge
- else if (strucmp( ps,"logger" )==0) err= logger::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "logger" )) err= logger::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#endif
#ifdef DBAPI_FILEOBJ // dbapi fileobj
- else if (strucmp( ps,"FILEOBJ" )==0) err= SDK_fileobj::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "FILEOBJ" )) err= SDK_fileobj::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef ADAPTITEM_SUPPORT // "script-like" adapt item
- else if (strucmp( ps,"ADAPTITEM" )==0) err= SDK_adapt::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "ADAPTITEM" )) err= SDK_adapt::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef UIAPI_DEMO // demo (C++) UI interface adapter, which will be delivered with SDK
- else if (strucmp( ps,"SDK_ui" )==0) err= SDK_ui::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "SDK_ui" )) err= SDK_ui::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef IPHONE_PLUGINS_STATIC // iPhone OS does not allow DLL plugins at this time, so we must link them statically
#ifdef HARDCODED_CONTACTS
- else if (strucmp( ps,"iPhone_addressbook")==0) err= iPhone_addressbook::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_addressbook")) err= iPhone_addressbook::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef HARDCODED_CALENDAR
- else if (strucmp( ps,"iPhone_calendar" )==0) err= iPhone_calendar::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_calendar" )) err= iPhone_calendar::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef HARDCODED_TODO
- else if (strucmp( ps,"iPhone_todos" )==0) err= iPhone_todos::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_todos" )) err= iPhone_todos::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef HARDCODED_NOTES
- else if (strucmp( ps,"iPhone_notes" )==0) err= iPhone_notes::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_notes" )) err= iPhone_notes::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef HARDCODED_EMAILS
- else if (strucmp( ps,"iPhone_emails" )==0) err= iPhone_emails::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_emails" )) err= iPhone_emails::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#ifdef HARDCODED_CUSTOM
- else if (strucmp( ps,"iPhone_db0" )==0) err= iPhone_db0::AssignMethods( aMod, aField,aFSize, aKey );
- else if (strucmp( ps,"iPhone_db1" )==0) err= iPhone_db1::AssignMethods( aMod, aField,aFSize, aKey );
- else if (strucmp( ps,"iPhone_db2" )==0) err= iPhone_db2::AssignMethods( aMod, aField,aFSize, aKey );
- else if (strucmp( ps,"iPhone_db3" )==0) err= iPhone_db3::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_db0" )) err= iPhone_db0::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_db1" )) err= iPhone_db1::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_db2" )) err= iPhone_db2::AssignMethods( aMod, aField,aFSize, aKey );
+ else if (BuiltIn( ps,n, "iPhone_db3" )) err= iPhone_db3::AssignMethods( aMod, aField,aFSize, aKey );
#endif
#endif
-
-
- else ModuleConnectionError( NULL, aName );
+ else if (strucmp( ps.c_str(), "#" )==0) err= LOCERR_UNKSUBSYSTEM;
+ else if (!BuiltIn( ps,n, "" )) ModuleConnectionError( NULL, AddBracks( ps ).c_str() );
return err;
} // DBApi_LibAssign
static void connect_no_dbapi( appPointer &aMod, API_Methods &m )
{
+ string no_dbapi= "";
+
DisconnectModule( aMod ); // avoid memory leak
ConnectModule ( aMod,"" ); // default: no db_api -> all methods return false
//---- module --------------------------------
- DBApi_LibAssign ( aMod,"", &m.start, sizeof(m.start), Plugin_Start );
- DBApi_LibAssign ( aMod,"", &m.param, sizeof(m.param), Plugin_Param );
- DBApi_LibAssign ( aMod,"", &m, sizeof(m) );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.start, sizeof(m.start), Plugin_Start );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.param, sizeof(m.param), Plugin_Param );
+ DBApi_LibAssign ( aMod,no_dbapi, &m, sizeof(m) );
//---- session -------------------------------
- DBApi_LibAssign ( aMod,"", &m.se, sizeof(m.se), Plugin_Session );
- DBApi_LibAssign ( aMod,"", &m.se.seAdapt, sizeof(m.se.seAdapt), Plugin_SE_Adapt );
- DBApi_LibAssign ( aMod,"", &m.se.seAuth, sizeof(m.se.seAuth), Plugin_SE_Auth );
- DBApi_LibAssign ( aMod,"", &m.se.dvAdmin, sizeof(m.se.dvAdmin), Plugin_DV_Admin );
- DBApi_LibAssign ( aMod,"", &m.se.dvTime, sizeof(m.se.dvTime), Plugin_DV_DBTime );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.se, sizeof(m.se), Plugin_Session );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.se.seAdapt, sizeof(m.se.seAdapt), Plugin_SE_Adapt );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.se.seAuth, sizeof(m.se.seAuth), Plugin_SE_Auth );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.se.dvAdmin, sizeof(m.se.dvAdmin), Plugin_DV_Admin );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.se.dvTime, sizeof(m.se.dvTime), Plugin_DV_DBTime );
//---- datastore -----------------------------
- DBApi_LibAssign ( aMod,"", &m.ds, sizeof(m.ds), Plugin_Datastore );
- DBApi_LibAssign ( aMod,"", &m.ds.dsg, sizeof(m.ds.dsg), Plugin_DS_General );
- DBApi_LibAssign ( aMod,"", &m.ds.dsAdapt, sizeof(m.ds.dsAdapt), Plugin_DS_Adapt );
- DBApi_LibAssign ( aMod,"", &m.ds.dsAdmin, sizeof(m.ds.dsAdmin), Plugin_DS_Admin );
- DBApi_LibAssign ( aMod,"", &m.ds.dsData, sizeof(m.ds.dsData), Plugin_DS_Data );
- DBApi_LibAssign ( aMod,"", &m.ds.dsData.str,sizeof(m.ds.dsData.str),Plugin_DS_Data_Str );
- DBApi_LibAssign ( aMod,"", &m.ds.dsData.key,sizeof(m.ds.dsData.key),Plugin_DS_Data_Key );
- DBApi_LibAssign ( aMod,"", &m.ds.dsBlob, sizeof(m.ds.dsBlob), Plugin_DS_Blob );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds, sizeof(m.ds), Plugin_Datastore );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsg, sizeof(m.ds.dsg), Plugin_DS_General );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsAdapt, sizeof(m.ds.dsAdapt), Plugin_DS_Adapt );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsAdmin, sizeof(m.ds.dsAdmin), Plugin_DS_Admin );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsData, sizeof(m.ds.dsData), Plugin_DS_Data );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsData.str,sizeof(m.ds.dsData.str),Plugin_DS_Data_Str );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsData.key,sizeof(m.ds.dsData.key),Plugin_DS_Data_Key );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ds.dsBlob, sizeof(m.ds.dsBlob), Plugin_DS_Blob );
//---- ui context ----------------------------
- DBApi_LibAssign ( aMod,"", &m.ui, sizeof(m.ui), Plugin_UI );
+ DBApi_LibAssign ( aMod,no_dbapi, &m.ui, sizeof(m.ui), Plugin_UI );
DisconnectModule( aMod ); // no longer used, avoid memory leak
} // connect_no_dbapi
TSyError err= LOCERR_OK;
if (FlagOK( aItem,aKey )) {
- if (is_lib) err= DBApi_LibAssign( fMod, fModName.c_str(), aField,aFieldSize, aKey );
+ if (is_lib) err= DBApi_LibAssign( fMod, fPlugin, aField,aFieldSize, aKey );
else { err= DB_Forbidden; // only allowed, if PLUGIN_DLL is active
#ifdef PLUGIN_DLL
- err= DBApi_DLLAssign( fMod, aField,aFieldSize, aKey, false );
+ err= DBApi_DLLAssign( fMod, aField,aFieldSize, aKey, false );
#endif
} // if
DEBUG_Exotic_INT( &fCB.Callback,MyDB, "DBApi_Assign", "aKey='%s' (size=%d) err=%d",
- aKey, aFieldSize, err );
+ aKey, aFieldSize, err );
} // if
return err;
NextToken ( fOptions, fModMain, " " ); // separate <mOptions>
fModName= fModMain;
CutBracks( fModMain );
+ fPlugin = fModMain;
if (in_bracks) fModName = AddBracks( fModName );
fSDKversion= pv( 0 ); // get the plugin's version before making the first tests
DEBUG_INT( mCB,MyDB, "Connect", "fSDKversion=%s", VersionStr( fSDKversion ).c_str() );
+ string sn= fModSub;
+ if (sn=="[#]" && !(fPlugin=="logger")) sn= ""; // remove the recursion breaker
+
CreateM_Func p= (CreateM_Func)m.start.Module_CreateContext;
- err= p( &mContext, fModMain.c_str(),fModSub.c_str(), mContextName, mCB );
+ err= p( &mContext, fModMain.c_str(), sn.c_str(), mContextName, mCB );
if (err==LOCERR_ALREADY) err= LOCERR_OK; // this is not an error, just avoid multiple assignment
DEBUG_INT( mCB,MyDB, "Connect", "mContext=%08X err=%d", mContext,err );
// !Supported( VP_EngineVersionParam ): only JNI signature changes
// !Supported( VP_MD5_Nonce_IN ): only JNI signature changes
- cAppCharP vda= Plugin_DS_Admin;
- if (!Supported( VP_InsertMapItem )) vda= Plugin_DS_Admin_OLD;
- cAppCharP vdd= Plugin_DS_Data;
- if (!Supported( VP_FLI_DSS )) vdd= Plugin_DS_Data_OLD2;
- if (!Supported( VP_ResumeToken )) vdd= Plugin_DS_Data_OLD1;
- cAppCharP vdb= Plugin_DS_Blob;
- if (!Supported( VP_DeleteBlob )) vdb= Plugin_DS_Blob_OLD;
+ cAppCharP vda= Plugin_DS_Admin;
+ if (!Supported( VP_InsertMapItem )) vda= Plugin_DS_Admin_OLD;
+ cAppCharP vdd= Plugin_DS_Data;
+ if (!Supported( VP_FLI_DSS )) vdd= Plugin_DS_Data_OLD2;
+ if (!Supported( VP_ResumeToken )) vdd= Plugin_DS_Data_OLD1;
+ cAppCharP vdb= Plugin_DS_Blob;
+ if (!Supported( VP_BLOB_JSignature )) vdb= Plugin_DS_Blob_OLD2; // new BLOB signature
+ if (!Supported( VP_DeleteBlob )) vdb= Plugin_DS_Blob_OLD1;
//---- module ---------------------------------
if (!err) err= DBApi_Assign( "", &m.param, sizeof(m.param), Plugin_Param );
{
typedef TSyError (*PlugProc)( CContext mContext,
cAppCharP mConfigParams, CVersion engineVersion );
- typedef TSyError (*OLD_PlugProc)( CContext mContext,
- cAppCharP mConfigParams ); // w/o <engineVersion>
+//typedef TSyError (*OLD_PlugProc)( CContext mContext,
+// cAppCharP mConfigParams ); // w/o <engineVersion>
TSyError err;
if (!fConnected) return DB_Error;
+ /*
// new param supported for Plugin Version >= 1.0.X.4
if (Supported( VP_EngineVersionParam )) {
PlugProc p= (PlugProc)m.param.Module_PluginParams;
OLD_PlugProc p= (OLD_PlugProc)m.param.Module_PluginParams; // w/o the SDK version parameter
err= p( mContext, mConfigParams );
} // if
+ */
+ PlugProc p= (PlugProc)m.param.Module_PluginParams;
+ err= p( mContext, mConfigParams, EngineSDKVersion() );
if (err==LOCERR_ALREADY) err= LOCERR_OK;
return err;
} // PluginParams
bool is_lib; // flag: as internal library
TDB_Api_Callback fCB; // Callback wrapper
- cAppCharP ModName() { return fModName.c_str(); } // the <moduleName>
- cAppCharP ModOptions() { return fOptions.c_str(); } // the module's parameters
+ cAppCharP ModName() { return fModName.c_str(); } // the <moduleName>
+ cAppCharP ModOptions() { return fOptions.c_str(); } // the module's parameters
+ cAppCharP ModPlugin() { return fPlugin.c_str(); } // the main module's name
+ cAppCharP ModMainName() { return fModMain.c_str(); } // the main module's name (with optional extension ":..."
+ cAppCharP ModSubName() { return fModSub.c_str(); } // the sub module's name (with params)
void DisposeStr( TDB_Api_Str &s );
private:
string fModName; // local copy of <aModName>
string fOptions; // local copy of module's paramters
- string fModMain; // main part of <aModName> w/o brackets
+ string fPlugin; // main part of <aModName> w/o brackets w/o extension
+ string fModMain; // main part of <aModName> w/o brackets, with optional extension
string fModSub; // sub part of <aModName> w/o brackets
string fDesc; // module's description
NULL );
} // if
- if (strcmp( aKey,Plugin_Param )==0 || // new AND old
- strcmp( aKey,Plugin_Param_OLD )==0) {
+ if (strcmp( aKey,Plugin_Param )==0) {
return ConnectFunctions( aMod, aField,aFieldSize, false,
// ---- plugin params
Module_PluginParams,
#endif
#endif
- #if !defined DISABLE_PLUGIN_DATASTOREADMIN || !defined DISABLE_PLUGIN_DATASTOREDATA
- if (strcmp( aKey,Plugin_DS_Blob )==0 || // new AND old
- strcmp( aKey,Plugin_DS_Blob_OLD )==0) {
+ #if !defined DISABLE_PLUGIN_DATASTOREADMIN || !defined DISABLE_PLUGIN_DATASTOREDATA
+ if (strcmp( aKey,Plugin_DS_Blob )==0 || // new AND old
+ strcmp( aKey,Plugin_DS_Blob_OLD1 )==0 ||
+ strcmp( aKey,Plugin_DS_Blob_OLD2 )==0) {
return ConnectFunctions( aMod, aField,aFieldSize, false,
// ---- BLOBs ----
ReadBlob,
NULL );
} // if
-
+ /*
// compatibility to older version ( w/o <engineVersion> )
keyOld= strcmp( aKey.c_str(),Plugin_Param_OLD )==0;
keyCur= strcmp( aKey.c_str(),Plugin_Param )==0;
// additional param for newer version
if (keyCur) js1= j.SgnS_X( jt + "I" ); // "(ILjava/lang/String;I)S"
else js1= jsT; // "(ILjava/lang/String;)S"
+ */
+
+ if (strcmp( aKey.c_str(),Plugin_Param )==0) {
+ // additional param for newer version
+ js1= j.SgnS_X( jt + "I" ); // "(ILjava/lang/String;I)S"
return ConnectFunctions( aMod, aField,aFieldSize, true,
// ---- start of plugin connection
NULL );
} // if
- keyOld= strcmp( aKey.c_str(),Plugin_DS_Blob_OLD )==0;
- keyCur= strcmp( aKey.c_str(),Plugin_DS_Blob )==0;
+ keyOld = strcmp( aKey.c_str(),Plugin_DS_Blob_OLD1 )==0;
+ keyOld2= strcmp( aKey.c_str(),Plugin_DS_Blob_OLD2 )==0;
+ keyCur = strcmp( aKey.c_str(),Plugin_DS_Blob )==0;
+
+ if (keyCur || keyOld || keyOld2) {
+ cAppCharP proc_delB= "";
+ if (keyCur) proc_delB= Da_DB;
- if (keyCur || keyOld) {
- const char* proc_delB= "";
- if (keyCur) proc_delB= Da_DB;
+ string bvsz= j.fvr; string bsz= j.fr;
+ if (!keyCur) { bvsz= jvi; bsz= "I"; }
- js1 = j.SgnS_X( jii // "(ILItemID;Ljava/lang/String;LVAR_byteArray; ...
- + jt // ... LVAR_int;LVAR_int;ZLVAR_boolean;)S"
+ js1 = j.SgnS_X( jii // "(ILItemID;Ljava/lang/String;LVAR_byteArray; ...
+ + jt // ... LVAR_int;LVAR_int;ZLVAR_boolean;)S"
+ LCP( jP, c_VAR_byteArray )
- + j.fvr
- + j.fvr + "Z"
+ + bvsz
+ + bvsz + "Z"
+ LCP( jP, c_VAR_bool ) );
- js2 = j.SgnS_X( jii + jt + "[B" + j.fr + j.fr + "ZZ" ); // "(ILItemID;Ljava/lang/String;[BIIZZ)S"
- js3 = j.SgnS_X( jii + jt ); // "(ILItemID;Ljava/lang/String;)S"
+ js2 = j.SgnS_X( jii + jt + "[B" + bsz + bsz + "ZZ" ); // "(ILItemID;Ljava/lang/String;[BIIZZ)S"
+ js3 = j.SgnS_X( jii + jt ); // "(ILItemID;Ljava/lang/String;)S"
return ConnectFunctions( aMod, aField,aFieldSize, true,
// ---- datastore data ----
# zero. When fixing something without interface change, increment
# REVISION.
ENGINE_CURRENT = 3
-ENGINE_REVISION = 0
+ENGINE_REVISION = 1
ENGINE_AGE = 3
CLEANFILES =
# zero. When fixing something without interface change, increment
# REVISION.
ENGINE_CURRENT = 3
-ENGINE_REVISION = 0
+ENGINE_REVISION = 1
ENGINE_AGE = 3
CLEANFILES =
# zero. When fixing something without interface change, increment
# REVISION.
ENGINE_CURRENT = 3
-ENGINE_REVISION = 0
+ENGINE_REVISION = 1
ENGINE_AGE = 3
CLEANFILES =
EXTRA_DIST = $(am__append_1)
#define WIN32 // needed for others
#endif
-// Release version status#undef RELEASE_VERSION
+// Release version status
+#undef RELEASE_VERSION
#define RELEASE_SYDEBUG 2 // extended DBG included
//#define OPTIONAL_SYDEBUG 1
#define DEFAULT_EMAILS_ONLYLAST true
#define DEFAULT_EMAILS_DAYSBEFORE 10
-// Outlook specifics
-// =================
-
// Eval limit options
// ==================
// Identification for update check and demo period
#define SYSER_VARIANT_CODE SYSER_VARIANT_PRO
-#define SYSER_PRODUCT_CODE SYSER_PRODCODE_CLIENT_OUTLOOK_PRO
+#define SYSER_PRODUCT_CODE SYSER_PRODCODE_CLIENT_LIB_WIN32
#define SYSER_EXTRA_ID SYSER_EXTRA_ID_PROTO
sysync_client_engine.so: $(OBJS)
$(LD) -shared -Xlinker -soname=sysync_client_engine $(LDFLAGS) $(OBJS) $(LIBS)\
- -o sysync_SDK/bin/Linux/sysync_client_engine.so
+ -o sysync_SDK/bin/Linux/sysync_client_engine.so
ifeq ($(TARGET), sysync_client_engine.so)
$(WDOP)/%.c.o: $(WD)/%.c
#endif
#ifndef SYSYNC_BUILDNUMBER
-#define SYSYNC_BUILDNUMBER 0
-#define SYSYNC_BUILDNUMBER_TXT "0"
+#define SYSYNC_BUILDNUMBER 5
+#define SYSYNC_BUILDNUMBER_TXT "5"
#endif
char buffer[bufsiz];
buffer[0]=0; // terminate for safety
string str;
+ string aSub;
struct passwd *userInfoP=NULL;
switch (aStringID) {
// My specific subdirectory for storing my app data/prefs
userInfoP = getpwuid(getuid());
aString = userInfoP->pw_dir; // user home dir
+ aSub = APPDATA_SUBDIR;
#ifdef ANDROID
- aString += "/data/com.sysync/" APPDATA_SUBDIR; // application specific subdir for android
+ aString += "/data/com.sysync"; // application specific subdir for android
+ if (!aSub.empty()) aString+= "/"; // slash only if subdir is really there
#else
- aString += "/.sysync/" APPDATA_SUBDIR; // application specific subdir
+ aString += "/.sysync/"; // application specific subdir
+ // don't adapt it here to avoid potential problems on other platforms
#endif
+ aString += aSub;
break;
#endif
/*
SML_API int smlLibStrncmp(const char *pTarget, const char *pSource, int count){
return strncmp((char *)pTarget, (char *)pSource, count);
}
+SML_API int smlLibStrnCasecmp(const char *pTarget, const char *pSource, int count){
+ return strncasecmp((char *)pTarget, (char *)pSource, count);
+}
SML_API String_t smlLibStrchr(const char *pString, char character){
return strchr((char *)pString, character);
}
SML_API_DEF String_t smlLibStrcat(const char *pTarget, const char *pSource) LIB_FUNC;
SML_API_DEF int smlLibStrcmp(const char *pTarget, const char *pSource) LIB_FUNC;
SML_API_DEF int smlLibStrncmp(const char *pTarget, const char *pSource, int count) LIB_FUNC;
+ SML_API_DEF int smlLibStrnCasecmp(const char *pTarget, const char *pSource, int count) LIB_FUNC;
SML_API_DEF String_t smlLibStrchr(const char *pString, char character) LIB_FUNC;
SML_API_DEF int smlLibStrlen(const char *pString) LIB_FUNC;
#endif
{ "gt", '>' },
{ "lt", '<' },
{ "apos", '\'' },
- { "quot", '"' }
+ { "quot", '"' },
+ { "#43", '+'}
};
MemPtr_t entity = pScanner->pos + 1;
int i;
for (;dtd->ext != SML_EXT_LAST; dtd++) {
const char *dtdname=dtd->name;
if (!dtdname) continue; /* skip empty names (should not appear but better be on the safe side) */
- if (dtd->ext==SML_EXT_UNDEFINED && smlLibStrncmp("SYNCML:SYNCML",ns,13)==0) {
+ if (dtd->ext==SML_EXT_UNDEFINED && smlLibStrnCasecmp("SYNCML:SYNCML",ns,13)==0) {
// SyncML namespace is ok without checking version!
ext = SML_EXT_UNDEFINED;
break;
// Note: create target also for not available datastores
TLocalDSList::iterator pos;
for (pos=fDatastores.begin();pos!=fDatastores.end();pos++) {
+ if ((*pos)->isAbstractDatastore()) continue; // don't try to create targets for abstract datastores (like superdatastores)
+ // non-abstract datastores at this point are always binfile-based by definition (this is a binfileimplclient, and this is one of its datastores)
TBinfileDSConfig *cfgP = static_cast<TBinfileDSConfig *>(*pos);
cfgP->initTarget(target,profile.profileID,aSetDefaults ? NULL : "",aSetDefaults && DEFAULT_DATASTORES_ENABLED); // remote datastore names default to local ones, empty if not default
// copy from template
// does not exist yet, create it now
TLocalDSList::iterator pos;
for (pos=fDatastores.begin();pos!=fDatastores.end();pos++) {
+ if ((*pos)->isAbstractDatastore()) continue; // only non-abstract datastores are guaranteed binfileds and have a target
TBinfileDSConfig *cfgP = static_cast<TBinfileDSConfig *>(*pos);
if (
cfgP->fLocalDBTypeID==aLocalDBTypeID &&
// detect special tunnel session's selection
bool tunnel = aProfileSelector==TUNNEL_PROFILE_ID;
// select profile if active
- if (fConfigP->fBinfilesActive) {
+ if (fConfigP->fBinfilesActive) {
if (tunnel) {
aProfileSelector=DEFAULT_PROFILE_ID;
}
virtual TFieldMapArrayItem *newFieldMapArrayItem(TCustomDSConfig *aCustomDSConfig, TConfigElement *aParentElement)
{ return new TFieldMapArrayItem(aCustomDSConfig,aParentElement); };
#endif
+ // returns false for datastores that are not abstract, i.e. have a backend implementation (=all stdlogicds derivates)
+ virtual bool isAbstractDatastore(void) { return false; }; // customimplds is the foundation for a implemented backend - so it is no longer abstract
protected:
// Add (probably datastore-specific) limits such as MaxSize and NoTruncate to types
virtual void addTypeLimits(TLocalEngineDS *aLocalDatastoreP, TSyncSession *aSessionP);
} // TDebugLoggerBase::DebugVPrintf
+// open new Block without attribute list
+void TDebugLoggerBase::DebugOpenBlock(cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed)
+{
+ // we need a format and debug not completely off
+ if (getMask() && aBlockName) {
+ DebugOpenBlock(aBlockName,aBlockTitle,aCollapsed,NULL);
+ }
+} // TDebugLoggerBase::DebugOpenBlock
+
+
// open new Block with attribute list, printf style
void TDebugLoggerBase::DebugOpenBlock(cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed, cAppCharP aBlockFmt, ...)
{
} // TDebugLoggerBase::DebugOpenBlockCollapsed
-// open new Block without attribute list
-void TDebugLoggerBase::DebugOpenBlock(cAppCharP aBlockName, cAppCharP aBlockTitle, bool aCollapsed)
-{
- // we need a format and debug not completely off
- if (getMask() && aBlockName) {
- static va_list va;
- DebugVOpenBlock(aBlockName,aBlockTitle,aCollapsed,NULL,va);
- }
-} // TDebugLoggerBase::DebugOpenBlock
-
-
// output text to debug channel
void TDebugLoggerBase::DebugPuts(uInt32 aDbgMask, cAppCharP aText, stringSize aTextSize, bool aPreFormatted)
{
// - flag static
engine->fCIisStatic= true;
// - prepare callback and pass to engine
- (*aCIP)->callbackVersion = aCallbackVersion;
- engine->fCI = *aCIP;
+ (*aCIP)->callbackVersion = aCallbackVersion; // fill in the outside callback version
+ engine->fCI = *aCIP; // engine uses the structure provided by the uiapp
// - connect the engine
err = engine->Connect("", aPrgVersion, aDebugFlags);
}
TLocalEngineDS *dsP = static_cast<TLocalEngineDS *>(aFuncContextP->getCallerContext());
aTermP->setAsString(dsP->getRemoteDatastore()->getFullName());
}; // func_RemoteDBName
-
+
#ifdef SYSYNC_CLIENT
return fail("Missing 'name' attribute in 'alias'");
fAliasNames.push_back(name);
expectEmpty();
- }
+ }
#endif
else if (strucmp(aElementName,"maxitemspermessage")==0)
expectUInt32(fMaxItemsPerMessage);
bool aFilterInclusive
)
{
+ // - set remote params
+ fRemoteDBPath=aRemoteDBPath;
+ AssignString(fDBUser,aDBUser);
+ AssignString(fDBPassword,aDBPassword);
+ // check for running under control of a superdatastore
+ // - aRemoteDBPath might contain a special prefix: "<super>remote", with "super" specifying the
+ // name of a local superdatastore to run the sync with
+ string opts;
+ if (!fRemoteDBPath.empty() && fRemoteDBPath.at(0)=='<') {
+ // we have an option prefix
+ size_t pfxe = fRemoteDBPath.find('>', 1);
+ if (pfxe!=string::npos) {
+ // extract options
+ opts.assign(fRemoteDBPath, 1, pfxe-1);
+ // store remote path cleaned from options
+ fRemoteDBPath.erase(0,pfxe+1);
+ }
+ }
+ if (!opts.empty()) {
+ #ifdef SUPERDATASTORES
+ // For now, the only option withing angle brackets is the name of the superdatastore, so opts==superdatastorename
+ // - look for superdatastore having the specified name
+ TSuperDSConfig *superdscfgP = static_cast<TSuperDSConfig *>(getSession()->getSessionConfig()->getLocalDS(opts.c_str()));
+ if (superdscfgP && superdscfgP->isAbstractDatastore()) {
+ // see if we have an instance of this already
+ fAsSubDatastoreOf = static_cast<TSuperDataStore *>(getSession()->findLocalDataStore(superdscfgP));
+ if (fAsSubDatastoreOf) {
+ // that superdatastore already exists, just override client sync params with those already set
+ aSyncMode = fAsSubDatastoreOf->fSyncMode;
+ aSlowSync = fAsSubDatastoreOf->fSlowSync;
+ aRecordFilterQuery = fAsSubDatastoreOf->fRemoteRecordFilterQuery.c_str();
+ }
+ else {
+ // instantiate new superdatastore
+ fAsSubDatastoreOf = static_cast<TSuperDataStore *>(superdscfgP->newLocalDataStore(getSession()));
+ if (fAsSubDatastoreOf) {
+ fSessionP->fLocalDataStores.push_back(fAsSubDatastoreOf);
+ // configure it with the same parameters as the subdatastore
+ if (!fAsSubDatastoreOf->dsSetClientSyncParams(
+ aSyncMode,
+ aSlowSync,
+ fRemoteDBPath.c_str(), // already cleaned from <xxx> prefix
+ aDBUser,
+ aDBPassword,
+ aLocalPathExtension,
+ aRecordFilterQuery,
+ aFilterInclusive
+ ))
+ return false; // failed
+ }
+ }
+ if (fAsSubDatastoreOf) {
+ // find link config for this superdatastore
+ TSubDSLinkConfig *lcfgP = NULL;
+ TSubDSConfigList::iterator pos;
+ for(pos=superdscfgP->fSubDatastores.begin();pos!=superdscfgP->fSubDatastores.end();pos++) {
+ if ((*pos)->fLinkedDSConfigP==fDSConfigP) {
+ // this is the link
+ lcfgP = *pos;
+ break;
+ }
+ }
+ if (lcfgP) {
+ // now link into superdatastore
+ fAsSubDatastoreOf->addSubDatastoreLink(lcfgP,this);
+ }
+ else {
+ PDEBUGPRINTFX(DBG_ERROR,("Warning: '%s' is not a subdatastore of '%s'", getName(), opts.c_str()));
+ return false; // failed
+ }
+ }
+ }
+ else {
+ PDEBUGPRINTFX(DBG_ERROR,("Warning: No superdatastore name '%s' exists -> can't run '%s' under superdatastore control", opts.c_str(), getName()));
+ return false; // failed
+ }
+ #endif // SUPERDATASTORES
+ }
// sync mode
fSyncMode=aSyncMode;
fSlowSync=aSlowSync;
fLocalDBPath+='/';
fLocalDBPath+=aLocalPathExtension;
}
- // - set remote params
- fRemoteDBPath=aRemoteDBPath;
- AssignString(fDBUser,aDBUser);
- AssignString(fDBPassword,aDBPassword);
// - we have the params for syncing now
return changeState(dssta_clientparamset)==LOCERR_OK;
} // TLocalEngineDS::dsSetClientSyncParams
-#endif
+#endif // SYSYNC_CLIENT
logop=0; // now consumed
paraNest++;
aFilter+='(';
+ p++;
}
else {
// must be term: ident op val
// this is not an error but only means end of filter expression
goto endFilter;
}
+ aFilter+=')';
paraNest--;
p++;
} while (true);
fSessionP->getReadOnly() || // session level read-only flag (probably set by login)
fDSConfigP->fReadOnly; // or datastore config
#ifdef SUPERDATASTORES
- // check if not already alerted as subdatastore
- if (fAsSubDatastoreOf) {
+ // if running as subdatastore of a superdatastore already, this call mus be from a superdatastore as well (aAsSubDatastoreOf!=NULL)
+ // Note: On a client, fAsSubDatastoreOf is set earlier in dsSetClientSyncParams()
+ // On a server, fAsSubDatastoreOf will be set now to avoid alerting as sub- and normal datastore at the same time.
+ if (fAsSubDatastoreOf && !aAsSubDatastoreOf) {
// bad, cannot be alerted directly AND as subdatastore
aStatusCommand.setStatusCode(400);
ADDDEBUGITEM(aStatusCommand,"trying to alert already alerted subdatastore");
return NULL;
}
// set subdatastore mode
- fAsSubDatastoreOf=aAsSubDatastoreOf;
+ fAsSubDatastoreOf = aAsSubDatastoreOf;
#endif
// reset type info
fLocalSendToRemoteTypeP = NULL;
fSyncMode
);
#endif // PROGRESS_EVENTS
- //%%% To make client-side filtering work, determining send/receive types must be done
- // before loading the sync set.
- // Therefore these two init steps are now in the new engInitForClientSync() routine, which is now called
- // in syncclient.cpp immediately before starting to generate sync commands.
- // (Alternatively, engInitForSyncOps() could be placed here before switching to dssta_dataaccessstarted.
- // Tried that, works, but has the disadvantage that in case server sends devInf after answering alerts,
- // type resolution would fail or be forced to blind flight)
- /*
- // - prepare engine for sync (determining types)
- // - let local datastore (derived DB-specific class) prepare for sync
- sta = changeState(dssta_dataaccessstarted);
- if (sta==LOCERR_OK && isStarted(false)) {
- // already started now, change state
- sta = changeState(dssta_syncsetready);
- }
- */
} // client Case
#endif // SYSYNC_CLIENT
}
}
#ifndef NO_REMOTE_RULES
// check if rule match type will override what we found so far
- if (fSessionP->fAppliedRemoteRuleP) {
+ if (!fSessionP->fActiveRemoteRules.empty()) {
// have a look at our rulematch types
TRuleMatchTypesContainer::iterator pos;
TSyncItemType *ruleMatchTypeP = NULL;
n=strlen(p);
e=p+n;
}
- // compare
- if (strwildcmp(fSessionP->fAppliedRemoteRuleP->getName(), p, 0, n)==0) {
- ruleMatchTypeP=(*pos).itemTypeP; // get the matching type
- break;
+ // see if that matches with any of the active rules
+ TRemoteRulesList::iterator apos;
+ for(apos=fSessionP->fActiveRemoteRules.begin();apos!=fSessionP->fActiveRemoteRules.end();apos++) {
+ if (strwildcmp((*apos)->getName(), p, 0, n)==0) {
+ ruleMatchTypeP=(*pos).itemTypeP; // get the matching type
+ break;
+ }
}
+ if (ruleMatchTypeP) break; // found a rule match type
// test next match target
p=e;
}
RemoteSendToLocalTypeP=remCorrTypeP;
// Show that we are using ruleMatch type
PDEBUGPRINTFX(DBG_DATA+DBG_HOT,(
- "Remote rule '%s' overrides default type usage - forcing type '%s' for send and receive",
- fSessionP->fAppliedRemoteRuleP->getName(),
+ "An active remote rule overrides default type usage - forcing type '%s' for send and receive",
ruleMatchTypeP->getTypeConfig()->getName()
));
// done
#ifdef SYSYNC_CLIENT
// initialize Sync alert for datastore according to Parameters set with dsSetClientSyncParams()
-localstatus TLocalEngineDS::engPrepareClientSyncAlert(TSuperDataStore *aAsSubDatastoreOf)
+localstatus TLocalEngineDS::engPrepareClientSyncAlert(void)
{
- localstatus sta;
-
#ifdef SUPERDATASTORES
- // check if not already alerted as subdatastore
- if (fAsSubDatastoreOf) {
- // bad, cannot be alerted directly AND as subdatastore
- DEBUGPRINTFX(DBG_ERROR,("trying to prepare alert for already alerted subdatastore"));
- return LOCERR_WRONGUSAGE;
- }
- // set subdatastore mode
- fAsSubDatastoreOf=aAsSubDatastoreOf;
+ // no operation here if running under control of a superdatastore.
+ // superdatastore's engPrepareClientSyncAlert() will call engPrepareClientRealDSSyncAlert of all subdatastores at the right time
+ if (fAsSubDatastoreOf)
+ return LOCERR_OK;
#endif
+ // this is a real datastore
+ return engPrepareClientDSForAlert();
+} // TLocalEngineDS::engPrepareClientSyncAlert
+
+
+
+// initialize Sync alert for datastore according to Parameters set with dsSetClientSyncParams()
+localstatus TLocalEngineDS::engPrepareClientDSForAlert(void)
+{
+ localstatus sta;
+
#ifdef SCRIPT_SUPPORT
// AlertPrepareScript to add filters and CGI
// - rebuild early (before all of the other DS scripts in makeAdminReady caused by engInitSyncAnchors below!)
// - save the identifying name of the DB
fIdentifyingDBName = fLocalDBPath;
// - get information about last session out of database
- sta=engInitSyncAnchors(
+ sta = engInitSyncAnchors(
relativeURI(fLocalDBPath.c_str()),
fRemoteDBPath.c_str()
);
if (fResumeAlertCode!=0 && fSessionP->getSyncMLVersion()>=syncml_vers_1_2) {
// we have a suspended session, try to resume
PDEBUGPRINTFX(DBG_PROTO,("Found suspended session with Alert Code = %hd",fResumeAlertCode));
- fResuming=true;
+ fResuming = true;
}
return LOCERR_OK; // ok
-} // TLocalEngineDS::engPrepareClientSyncAlert
+} // TLocalEngineDS::engPrepareClientDSForAlert
// generate Sync alert for datastore after initialisation with engPrepareClientSyncAlert()
{
aAlertCommandP=NULL;
#ifdef SUPERDATASTORES
- if (fAsSubDatastoreOf) return LOCERR_OK; // NOP, ok
+ if (fAsSubDatastoreOf) return LOCERR_OK; // NOP, ok, only superdatastore creates an alert!
#endif
PDEBUGPRINTFX(DBG_PROTO,(
// - determine types to exchange
// - make sync set ready
localstatus TLocalEngineDS::engInitForClientSync(void)
+{
+ #ifdef SUPERDATASTORES
+ // no init in case we are under control of a superdatastore -> the superdatastore will do that
+ if (fAsSubDatastoreOf)
+ return LOCERR_OK;
+ #endif
+ return engInitDSForClientSync();
+} // TLocalEngineDS::engInitForClientSync
+
+
+
+// Init engine for client sync
+// - determine types to exchange
+// - make sync set ready
+localstatus TLocalEngineDS::engInitDSForClientSync(void)
{
- // - prepare engine for sync (determining types)
+ // make ready for syncops
localstatus sta = engInitForSyncOps(getRemoteDBPath());
if (sta==LOCERR_OK) {
// - let local datastore (derived DB-specific class) prepare for sync
}
}
return sta;
-} // TLocalEngineDS::engInitForClientSync
+} // TLocalEngineDS::engInitDSForClientSync
#endif // Client
/// @note superdatastore does it itself to have correct order of things happening
void TLocalEngineDS::engRequestEnded(void)
{
- // variant for independent non-super/non-sub datastore
- if (!fAsSubDatastoreOf) {
- // If DS 1.2: Make sure everything is ready for a resume in case there's an abort (implicit Suspend)
- // before the next request. Note that the we cannot wait for session timeout, as the resume attempt
- // from the client probably arrives much earlier.
- // Note: It is ESSENTIAL not to save the state until sync set is ready, because saving state will
- // cause DB access, and DB access is not permitted while sync set is possibly still loading
- // (possibly in a separate thread!). So dssta_syncmodestable (as in <=3.0.0.2) is NOT enough here!
- if (testState(dssta_syncsetready)) {
- // make sure all unsent items are marked for resume
- engSaveSuspendState(false); // only if not already aborted
- }
- // let datastore prepare for end of request
- dsRequestEnded();
- // and let it prepare for end of this thread as well
- dsThreadMayChangeNow();
+ #ifdef SUPERDATASTORES
+ if (fAsSubDatastoreOf)
+ return;
+ #endif
+ // If DS 1.2: Make sure everything is ready for a resume in case there's an abort (implicit Suspend)
+ // before the next request. Note that the we cannot wait for session timeout, as the resume attempt
+ // from the client probably arrives much earlier.
+ // Note: It is ESSENTIAL not to save the state until sync set is ready, because saving state will
+ // cause DB access, and DB access is not permitted while sync set is possibly still loading
+ // (possibly in a separate thread!). So dssta_syncmodestable (as in <=3.0.0.2) is NOT enough here!
+ if (testState(dssta_syncsetready)) {
+ // make sure all unsent items are marked for resume
+ engSaveSuspendState(false); // only if not already aborted
}
+ // let datastore prepare for end of request
+ dsRequestEnded();
+ // and let it prepare for end of this thread as well
+ dsThreadMayChangeNow();
} // TLocalEngineDS::engRequestEnded
#endif // SYSYNC_SERVER
}
else {
// if the DB has a error string to show, add it here
- aStatusCommand.addItemString(lastDBErrorText().c_str());
+ aStatusCommand.addItemString(lastDBErrorText().c_str());
}
return ok;
}
do {
// check if already done
if (pos==fPendingAddMaps.end()) break; // done
- // add item
+ // get ID
string locID = (*pos).first;
dsFinalizeLocalID(locID); // make sure we have the permanent version in case datastore implementation did deliver temp IDs
- // add local ID prefix, if any
- if (aLocalIDPrefix && *aLocalIDPrefix)
- locID.insert(0,aLocalIDPrefix);
+ // create prefixed version of ID
+ string prefixedLocID;
+ AssignString(prefixedLocID, aLocalIDPrefix); // init with prefix (if any)
+ prefixedLocID += locID; // append local ID
// add it to map command
- aMapCommandP->addMapItem(locID.c_str(),(*pos).second.c_str());
+ aMapCommandP->addMapItem(prefixedLocID.c_str(),(*pos).second.c_str());
// check if we could send this command
#ifdef USE_SML_EVALUATION
if (
// yes, it should work
PDEBUGPRINTFX(DBG_PROTO,(
"Mapitem generated: localID='%s', remoteID='%s'",
- locID.c_str(),
+ prefixedLocID.c_str(),
(*pos).second.c_str()
));
- // move sent ones to unconfirmed list
+ // move sent ones to unconfirmed list (Note: use real locID, without prefix!)
fUnconfirmedMaps[locID]=(*pos).second;
// remove item from to-be-sent list
TStringToStringMap::iterator temp_pos = pos++; // make copy and set iterator to next
virtual void clear();
// - check for alias names
uInt16 isDatastoreAlias(cAppCharP aDatastoreURI);
+ // - returns true for datastores that are abstract, i.e. don't have a backend implementation (like superdatastores, or non-derived localengineds)
+ virtual bool isAbstractDatastore(void) { return true; }; // pure localengineds is abstract. First derivate towards backend (stdlogicds) will override this with "false".
protected:
// check config elements
#ifndef HARDCODED_CONFIG
#ifdef SYSYNC_CLIENT
/// initialize Sync alert for datastore according to Parameters set with dsSetClientSyncParams()
/// @note initializes anchors and makes calls to isFirstTimeSync() valid
- localstatus engPrepareClientSyncAlert(TSuperDataStore *aAsSubDatastoreOf);
+ SUPERDS_VIRTUAL localstatus engPrepareClientSyncAlert(void);
+ /// internal helper to be called by engPrepareClientSyncAlert() from this class and from superdatastore
+ localstatus engPrepareClientDSForAlert(void);
/// generate Sync alert for datastore
/// @note this could be repeatedly called due to auth failures at beginning of session
/// @note this is a NOP for subDatastores (should not be called in this case, anyway)
localstatus engGenerateClientSyncAlert(TAlertCommand *&aAlertCommandP);
- // Init engine for client sync
+ // Init engine for client sync (superdatastore aware)
// - determine types to exchange
// - make sync set ready
- localstatus engInitForClientSync(void);
+ SUPERDS_VIRTUAL localstatus engInitForClientSync(void);
+ // - non-superdatastore aware base functionality
+ localstatus engInitDSForClientSync(void);
#endif
/// Internal events during sync for derived classes
/// @note local DB authorisation must be established already before calling these
fDoNotFoldContent = false; // standard requires folding
fTreatRemoteTimeAsLocal = false; // only for broken implementations
fTreatRemoteTimeAsUTC = false; // only for broken implementations
- fAppliedRemoteRuleP = NULL; // no dependency
+ fActiveRemoteRules.clear(); // no dependency on certain remote rules
} // TMimeDirProfileHandler::TMimeDirProfileHandler
// - just remember
otherRulePropP=propP;
}
- else if (propP->ruleDependency==fAppliedRemoteRuleP) {
+ else if (isActiveRule(propP->ruleDependency)) {
// specific for the applied rule
expandPropP=propP; // default to expand current prop
// now we have expanded a rule-specific property (blocks expanding of "other"-rule dependent prop)
// - just remember for now
otherRulePropP=propP;
}
- else if (propP->ruleDependency==fAppliedRemoteRuleP) {
+ else if (isActiveRule(propP->ruleDependency)) {
// specific for the applied rule
parsePropP=propP; // default to expand current prop
// now we have expanded a rule-specific property (blocks parsing of "other"-rule dependent prop)
fDoNotFoldContent = fRelatedDatastoreP->getSession()->fDoNotFoldContent;
fTreatRemoteTimeAsLocal = fRelatedDatastoreP->getSession()->fTreatRemoteTimeAsLocal;
fTreatRemoteTimeAsUTC = fRelatedDatastoreP->getSession()->fTreatRemoteTimeAsUTC;
- fAppliedRemoteRuleP =
- #ifndef NO_REMOTE_RULES
- fRelatedDatastoreP->getSession()->fAppliedRemoteRuleP;
- #else
- NULL;
- #endif
+ #ifndef NO_REMOTE_RULES
+ fActiveRemoteRules = fRelatedDatastoreP->getSession()->fActiveRemoteRules; // copy the list
+ #endif
}
}
#ifndef NO_REMOTE_RULES
+
void TMimeDirProfileHandler::setRemoteRule(const string &aRemoteRuleName)
{
TSessionConfig *scP = getSession()->getSessionConfig();
TRemoteRulesList::iterator pos;
for(pos=scP->fRemoteRulesList.begin();pos!=scP->fRemoteRulesList.end();pos++) {
if((*pos)->fElementName == aRemoteRuleName) {
- fAppliedRemoteRuleP = *pos;
+ // only this rule must be active
+ fActiveRemoteRules.clear();
+ fActiveRemoteRules.push_back(*pos);
break;
}
}
} // TMimeDirProfileHandler::setRemoteRule
-#endif
+
+
+// check if given rule (by name, or if aRuleName=NULL by rule pointer) is active
+bool TMimeDirProfileHandler::isActiveRule(TRemoteRuleConfig *aRuleP)
+{
+ TRemoteRulesList::iterator pos;
+ for(pos=fActiveRemoteRules.begin();pos!=fActiveRemoteRules.end();pos++) {
+ if ((*pos)==aRuleP)
+ return true;
+ }
+ // no match
+ return false;
+} // TMimeDirProfileHandler::isActiveRule
+
+#endif // NO_REMOTE_RULES
// - check mode
// - time handling
bool fTreatRemoteTimeAsLocal;
bool fTreatRemoteTimeAsUTC;
- // - dependency on certain remote rule
- TRemoteRuleConfig *fAppliedRemoteRuleP;
+ #ifndef NO_REMOTE_RULES
+ // - dependency on certain remote rule(s)
+ TRemoteRulesList fActiveRemoteRules; // list of active remote rules that might influence behaviour
+ bool isActiveRule(TRemoteRuleConfig *aRuleP); // check if given rule is among the active ones
+ #endif
// vars
TMIMEProfileConfig *fProfileCfgP; // the MIME-DIR profile config element
// property definitions
}
-// negative aAtLeastDays allowed only with aModulo==1 (because of undefined % operator for negatives - altough it is normally truncate towards zero = remainder)
-// - advances cursor by at least aAtLeastDays
-// - if advance is more than aNoModuloDays, advance will be one aModulo interval
-static void adjustCursor(TRRuleExpandStatus &es, lineardate_t aAtLeastDays, sInt16 aModulo=1, sInt16 aNoModuloDays=0)
+// advance cursor by given number of days
+static void adjustCursor(TRRuleExpandStatus &es, lineardate_t aDays)
{
- lineardate_t days = 0;
- days = aAtLeastDays; // default to simply add days
- if (aModulo>1) {
- // we need to make sure remainder is 0 and advance extra
- lineardate_t extradays = aAtLeastDays % aModulo;
- // only if extradays exceeds given range (which usually represents the reach of the current mask, e.g. remaining days in the week)
- if (extradays>aNoModuloDays) {
- days += aModulo-extradays;
- }
- }
// now days = number of days to advance
- es.cursor += days*linearDateToTimeFactor;
+ es.cursor += aDays*linearDateToTimeFactor;
// adjust weekday
- es.cursorWDay += days % DaysPerWk;
+ es.cursorWDay += aDays % DaysPerWk;
if (es.cursorWDay<0) es.cursorWDay += DaysPerWk;
else if (es.cursorWDay>=DaysPerWk) es.cursorWDay -= DaysPerWk;
#ifdef SYNTHESIS_UNIT_TEST
#endif
}
+
+static lineardate_t makeMultiple(lineardate_t d, sInt16 aMultiple, sInt16 aMaxRemainder=0)
+{
+ if (aMultiple>1) {
+ // we need to make sure remainder is 0 and advance extra
+ lineardate_t r = d % aMultiple; // remainder
+ if (r>aMaxRemainder) {
+ // round up to next multiple
+ d += aMultiple - r;
+ }
+ }
+ return d;
+}
+
+
// simple and fast cursor increment
static void incCursor(TRRuleExpandStatus &es)
{
// Daily: can be calculated directly
if (!es.started) {
// calculate first occurrence
- adjustCursor(es, es.expansionStartDayOffset, es.interval); // move cursor to first day
+ adjustCursor(es, makeMultiple(es.expansionStartDayOffset, es.interval)); // move cursor to first day
}
else {
// calculate next occurrence
if (es.firstmask==0)
es.firstmask = 1<<es.cursorWDay; // set start day in mask
// advance cursor to first day of expansion period
- sInt16 woffs = es.cursorWDay-es.weekstart; // how many days back to next week start
- if (woffs<0) woffs+=DaysPerWk; // we want to go BACK to next week start
- adjustCursor(es, -woffs, 1); // back to previous start of week
- adjustCursor(es, es.expansionStartDayOffset, es.interval*DaysPerWk, DaysPerWk-woffs-1); // advance by intervals when advance exeeds rest of week (covered by mask)
- adjustCursor(es, woffs, 1); // forward again to start weekday
+ // - go back to start of very first week covered by the recurrence
+ sInt16 woffs = es.cursorWDay-es.weekstart; // how many days back to next week start from dtstart
+ if (woffs<0) woffs+=DaysPerWk; // we want to go BACK to previous week start
+ adjustCursor(es, -woffs); // back to previous start of week (=start of first week covered by recurrence)
+ lineardate_t d = es.expansionStartDayOffset+woffs; // days from beginning of first week to beginning day of expansion
+ // if we exceed reach of mask in current interval, round up to beginning of next interval
+ d = makeMultiple(d,es.interval*DaysPerWk,DaysPerWk-1); // expand into next interval if needed
+ adjustCursor(es, d); // now advance cursor to
if (expansionEnd(es)) goto done; // could by beyond current expanding scope due to interval jump
}
// calculate first/next occurrence (if not first occurrence, do not check initially but advance first)
// string REMOTERULENAME()
- // returns name of applied remote rule, empty if none
+ // returns name of the LAST matched remote rule (or subrule), empty if none
+ // Note: this is legacy from 3.4.0.4 onwards, as we now have a list of multiple active rules
static void func_Remoterulename(TItemField *&aTermP, TScriptContext *aFuncContextP)
{
#ifndef NO_REMOTE_RULES
- string r;
if (aFuncContextP->getSession()) {
// there is a session
- if (aFuncContextP->getSession()->fAppliedRemoteRuleP) {
- // there is a rule applied
- aTermP->setAsString(aFuncContextP->getSession()->fAppliedRemoteRuleP->getName());
+ if (!aFuncContextP->getSession()->fActiveRemoteRules.empty()) {
+ // there is at least one rule applied, get the last one in the list
+ aTermP->setAsString(aFuncContextP->getSession()->fActiveRemoteRules.back()->getName());
return;
}
}
}; // func_Remoterulename
+ // boolean ISACTIVERULE(string rulename)
+ // checks if given rule is currently activated
+ static void func_isActiveRule(TItemField *&aTermP, TScriptContext *aFuncContextP)
+ {
+ #ifndef NO_REMOTE_RULES
+ string r;
+ aFuncContextP->getLocalVar(0)->getAsString(r);
+ if (aFuncContextP->getSession()) {
+ // there is a session, return status
+ aTermP->setAsBoolean(aFuncContextP->getSession()->isActiveRule(r.c_str()));
+ return;
+ }
+ #endif
+ // remote rules not supported or no session active
+ aTermP->assignEmpty();
+ }; // func_Remoterulename
+
+
+
+
// TREATASLOCALTIME(integer flag)
static void func_SetTreatAsLocaltime(TItemField *&aTermP, TScriptContext *aFuncContextP)
{
if (profileHandlerP) {
// now we can convert
// - set the mode code (none = 0 = default)
- // TODO? Shouldn't this check whether arg #2 was passed at all? If not,
- // the code will segfault when trying to call getAsInteger()
profileHandlerP->setProfileMode(aFuncContextP->getLocalVar(2)->getAsInteger());
profileHandlerP->setRelatedDatastore(NULL); // no datastore in particular is related
-#ifndef NO_REMOTE_RULES
+ #ifndef NO_REMOTE_RULES
// - try to find remote rule
TItemField *field = aFuncContextP->getLocalVar(3);
if (field) {
if (!s.empty())
profileHandlerP->setRemoteRule(s);
}
-#endif
+ #endif
// - convert
aFuncContextP->getLocalVar(0)->getAsString(s);
ok = profileHandlerP->parseText(s.c_str(), s.size(), *itemP);
{ "SWAP", TBuiltinStdFuncs::func_Swap, fty_none, 2, param_swap },
{ "TYPENAME", TBuiltinStdFuncs::func_TypeName, fty_string, 1, param_oneVariant },
{ "REMOTERULENAME", TBuiltinStdFuncs::func_Remoterulename, fty_string, 0, NULL },
+ { "ISACTIVERULE", TBuiltinStdFuncs::func_isActiveRule, fty_integer, 1, param_oneString },
{ "LOCALURI", TBuiltinStdFuncs::func_LocalURI, fty_string, 0, NULL },
{ "NOW", TBuiltinStdFuncs::func_Now, fty_timestamp, 0, NULL },
{ "SYSTEMNOW", TBuiltinStdFuncs::func_SystemNow, fty_timestamp, 0, NULL },
&DBFuncTable, // context's function table
this // datastore pointer needed for context
);
+ // - datastoreinitscript might abort the sync with this datastore, check for that and exit if so
+ if (isAborted()) {
+ return getAbortStatusCode();
+ }
#endif
// - init post fetch filtering, sets fFilteringNeededForAll and fFilteringNeeded correctly
initPostFetchFiltering();
&DBFuncTable, // context's function table
this // datastore pointer needed for context
);
+ // - datastoreinitscript might abort the sync with this datastore, check for that and exit if so
+ if (isAborted()) {
+ return getAbortStatusCode();
+ }
#endif
// - init post fetch filtering, sets fFilteringNeededForAll and fFilteringNeeded correctly
initPostFetchFiltering();
virtual bool isStarted(bool aWait);
/// @}
-
protected:
/// @name dsXXXX (usually abstract) virtuals defining the interface to derived datastore classes (implementation, api)
/// These are usually designed such that they should always call inherited::dsXXX to let the entire chain
SYSYNC_THROW(TSyncException(DEBUGTEXT("TSuperDataStore::TSuperDataStore called with NULL config","lds1")));
// reset first
InternalResetDataStore();
- // create links to subdatastores
- TSubDSConfigList::iterator pos;
- TSubDatastoreLink link;
- for(pos=aDSConfigP->fSubDatastores.begin();pos!=aDSConfigP->fSubDatastores.end();pos++) {
- // start not yet pending
- link.fStartPending=false;
- // set link to subdatastore link config
- link.fDSLinkConfigP=*pos;
- // find actual datastore by "handle" (= config pointer)
- link.fDatastoreLinkP=aSessionP->findLocalDataStore(link.fDSLinkConfigP->fLinkedDSConfigP);
- // if actual datastore does not yet exist, create it now. This can be
- // the case for clients, where datastores are only instantiated when
- // directly addressed by a SyncRequest (which will not happen for
- // subdatastores normally)
- if (!link.fDatastoreLinkP) {
- // add
- link.fDatastoreLinkP=aSessionP->addLocalDataStore(link.fDSLinkConfigP->fLinkedDSConfigP);
+ // for server, all configured subdatastores are automatically linked in
+ // (for client, only those that are active will be linked in at dsSetClientParams() time)
+ if (IS_SERVER) {
+ // create links to subdatastores
+ TSubDSConfigList::iterator pos;
+ for(pos=aDSConfigP->fSubDatastores.begin();pos!=aDSConfigP->fSubDatastores.end();pos++) {
+ // add link
+ addSubDatastoreLink(*pos,NULL); // search datastore
}
- // save link
- fSubDSLinks.push_back(link);
}
- // Important: We need to get the iterator now again, as the implicit
- // iterator init via InternalResetDataStore() is invalid because the list was empty then.
- fCurrentGenDSPos=fSubDSLinks.begin();
} // TSuperDataStore::TSuperDataStore
+void TSuperDataStore::addSubDatastoreLink(TSubDSLinkConfig *aDSLinkConfigP, TLocalEngineDS *aDatastoreP)
+{
+ TSubDatastoreLink link;
+ // start not yet pending
+ link.fStartPending = false;
+ // set link to subdatastore's config
+ link.fDSLinkConfigP = aDSLinkConfigP;
+ if (aDatastoreP)
+ link.fDatastoreLinkP = aDatastoreP; // we already know the datastore (for client, it might not yet be in session list of datastores)
+ else
+ link.fDatastoreLinkP = fSessionP->findLocalDataStore(link.fDSLinkConfigP->fLinkedDSConfigP); // find actual datastore by "handle" (= config pointer)
+ // make sure datastore is instantiated
+ if (!link.fDatastoreLinkP) {
+ // instantiate now (should not happen on server, as all datastores are instantiated on a server anyway)
+ link.fDatastoreLinkP=fSessionP->addLocalDataStore(link.fDSLinkConfigP->fLinkedDSConfigP);
+ }
+ // save link
+ fSubDSLinks.push_back(link);
+ // Important: We need to get the iterator now again, in case the list was empty before
+ // (because the iterator set in InternalResetDataStore() is invalid because it was created for an empty list).
+ fCurrentGenDSPos=fSubDSLinks.begin();
+}
+
+
void TSuperDataStore::InternalResetDataStore(void)
{
// init
substatus // status that might be modified
);
if (subalertcmdP) {
- // get rid of this, we don't need it
+ // get rid of this, we don't need it (server case only, client case does not generate an alert command here anyway)
delete subalertcmdP;
}
- else {
+ // check if processing alert had a problem
+ if (substatus.getStatusCode()!=0) {
// basic problem with one of the subdatastores
// - propagate error code
aStatusCommand.setStatusCode(substatus.getStatusCode());
- // - cancel alert
+ // - no alert to send
return NULL;
}
// this one is pending for start
// ----------------------------------
-// Abstracts of TLocalEngineDS
-// ----------------------------
-
// called at sync alert (before generating for client, after receiving for server)
// - obtains combined anchor from subdatastores
// - combines them into a common anchor (if possible)
// - updates fFirstTimeSync as well
localstatus TSuperDataStore::engInitSyncAnchors(
- cAppCharP aDatastoreURI, // local datastore URI
- cAppCharP aRemoteDBID // ID of remote datastore (to find session information in local DB)
+ cAppCharP aDatastoreURI, // (Note: unused in superdatastore) local datastore URI
+ cAppCharP aRemoteDBID // (Note: unused in superdatastore) ID of remote datastore (to find session information in local DB)
)
{
bool allanchorsequal=true;
TSubDSLinkList::iterator pos;
for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
if (pos==fSubDSLinks.begin()) {
- /* not needed, because engInitSyncAnchors() will be called only after all subdatastore's
- engProcessSyncAlert() was called, which in turn contains a call to engInitSyncAnchors()
- This means we can safely assume we have the fLastRemoteAnchor/fNextLocalAnchor info
- ready here.
- In fact, calling this here AGAIN had the effect that the state of the first
- subdatastore would be set BACK to dssta_adminready (instead of the required dssta_syncmodestable,
- and in turn when the first sync command arrived, it would be rejected with "SYNC received too early".
- // init anchors of subdatastore
- sta = pos->fDatastoreLinkP->engInitSyncAnchors(aDatastoreURI, aRemoteDBID);
- if (sta!=LOCERR_OK)
- break; // exit, we cannot init
- */
- // assign references of first datastore
- // - this must be same from all subdatastores
+ // Server case note:
+ // Subdatastore's engInitSyncAnchors() MUST NOT be called here, because this routine will
+ // always be called after all subdatastore's engProcessSyncAlert() was called
+ // which in turn contains a call to engInitSyncAnchors().
+ // Client case note:
+ // Subdatastore's engInitSyncAnchors() MUST NOT be called here, because this routine will
+ // be called from TSuperDataStore::engPrepareClientSyncAlert() after iterating through
+ // subdatastores and calling their engPrepareClientDSForAlert(), which in turn
+ // contains a call to engInitSyncAnchors().
+ // This means we can safely assume we have the fLastRemoteAnchor/fNextLocalAnchor info
+ // ready here.
+ // - Assign references of first datastore
+ // Note: remote anchor must be same from all subdatastores
fLastRemoteAnchor=pos->fDatastoreLinkP->fLastRemoteAnchor;
// - these are used from the first datastore, and might differ (a few seconds,
// that is) for other datastores
#ifdef SYSYNC_CLIENT
+// Client only: initialize Sync alert for datastore according to Parameters set with dsSetClientSyncParams()
+localstatus TSuperDataStore::engPrepareClientSyncAlert(void)
+{
+ localstatus sta;
+
+ // not resuming by default
+ fResuming = false;
+ fResumeAlertCode = 0;
+ // prepare all subdatastores that were parametrized to participate in a sync by dsSetClientSyncParams()
+ TSubDSLinkList::iterator pos;
+ for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
+ TLocalEngineDS *dsP = pos->fDatastoreLinkP;
+ if (dsP->testState(dssta_clientparamset)) {
+ // configured for sync, prepare for alert
+ sta = dsP->engPrepareClientDSForAlert();
+ if (sta!=LOCERR_OK)
+ return sta; // error
+ // collect slow sync status
+ fSlowSync = fSlowSync || dsP->fSlowSync;
+ // collect resume alert code
+ if (dsP->fResuming) {
+ // subdatastore would like to resume
+ if (fResumeAlertCode!=0 && fResumeAlertCode!=dsP->fResumeAlertCode) {
+ // different idea about what to resume -> can't resume
+ PDEBUGPRINTFX(DBG_ERROR,("subdatastores differ in resume alert code -> cancel resume of superdatastore"));
+ fResuming = false;
+ }
+ else {
+ // resume is possible (but might be cancelled if another subdatastore disagrees
+ fResumeAlertCode = dsP->fResumeAlertCode;
+ fResuming = true;
+ }
+ }
+ }
+ }
+ // now init my own anchors and firstsync state, which are a combination of my subdatastore's
+ sta = engInitSyncAnchors(NULL,NULL);
+ if (sta!=LOCERR_OK)
+ return sta; // error
+ // determine final resume state
+ if (fResuming) {
+ PDEBUGPRINTFX(DBG_PROTO,("Found suspended session with Alert Code = %hd for all subdatastores",fResumeAlertCode));
+ }
+ else {
+ // superdatastore can't resume, cancel all subdatastore's resumes that might be set
+ for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
+ pos->fDatastoreLinkP->fResuming = false;
+ }
+ }
+ // all successful
+ return LOCERR_OK;
+} // TSuperDataStore::engPrepareClientSyncAlert
+
+
+
+// Init engine for client sync
+// - determine types to exchange
+// - make sync set ready
+localstatus TSuperDataStore::engInitForClientSync(void)
+{
+ localstatus sta = LOCERR_OK;
+ // first let all subdatastores init for sync
+ TSubDSLinkList::iterator pos;
+ for (pos=fSubDSLinks.begin();pos!=fSubDSLinks.end();pos++) {
+ sta = pos->fDatastoreLinkP->engInitDSForClientSync();
+ if (sta!=LOCERR_OK)
+ return sta;
+ }
+ // now change my own state
+ return inherited::engInitDSForClientSync();
+} // TSuperDataStore::engInitForClientSync
+
+
+
+
+
+
// Client only: returns number of unsent map items
sInt32 TSuperDataStore::numUnsentMaps(void)
{
if (pos==fSubDSLinks.end()) break; // done
// create current prefix
AssignString(prefix,aLocalIDPrefix);
- prefix.append(fCurrentGenDSPos->fDSLinkConfigP->fGUIDPrefix);
+ prefix.append(pos->fDSLinkConfigP->fGUIDPrefix);
// generate Map items
ok=pos->fDatastoreLinkP->engGenerateMapItems(aMapCommandP,prefix.c_str());
// exit if not yet finished with generating map items for this datastore
TSuperDataStore(TSuperDSConfig *aDSConfigP, TSyncSession *aSessionP, const char *aName, uInt32 aCommonSyncCapMask=0);
virtual ~TSuperDataStore();
virtual void dsResetDataStore(void) { InternalResetDataStore(); inherited::dsResetDataStore(); };
+ // add links to subdatastores
+ void addSubDatastoreLink(TSubDSLinkConfig *aDSLinkConfigP, TLocalEngineDS *aDatastoreP);
// abort
virtual void engAbortDataStoreSync(TSyError aReason, bool aLocalProblem, bool aResumable=true);
virtual bool isAborted(void); // test abort status
// - returns true if DB implementation supports resume (saving of resume marks, alert code, pending maps, tempGUIDs)
virtual bool dsResumeSupportedInDB(void);
#ifdef SYSYNC_CLIENT
+ // Client only: initialize Sync alert for datastore according to Parameters set with dsSetClientSyncParams()
+ /// @note initializes anchors and makes calls to isFirstTimeSync() valid
+ virtual localstatus engPrepareClientSyncAlert(void);
+ // Client only: init engine for client sync (superdatastore aware)
+ virtual localstatus engInitForClientSync(void);
// Client only: called to generate Map items
// - Returns true if now finished for this datastore
// - also sets fState to dss_done when finished
else
#endif
{
- if (!getLocalDeviceID(fLocalURI) || devidWithUserHash()) {
+ if (!getSyncAppBase()->getMyDeviceID(fLocalURI) || devidWithUserHash()) {
// Device ID is not really unique, make a hash including user name to make it pseudo-unique
// create MD5 hash from non-unique ID and user name
// Note: when compiled with GUARANTEED_UNIQUE_DEVICID, devidWithUserHash() is always false.
bool anyslowsyncs=false;
TLocalEngineDS *localDS;
for (pos=fLocalDataStores.begin(); pos!=fLocalDataStores.end(); ++pos) {
- // prepare alert
+ // prepare alert (Note: datastore may be run by a superdatastore)
localDS = *pos;
- status=localDS->engPrepareClientSyncAlert(NULL); // not as superdatastore
+ status=localDS->engPrepareClientSyncAlert();
if (status!=LOCERR_OK) {
// local database error
return localError(status); // not found
localDS = *pos;
if (!localDS->isSubDatastore()) {
TAlertCommand *alertcmdP;
- status=localDS->engGenerateClientSyncAlert(alertcmdP);
+ status = localDS->engGenerateClientSyncAlert(alertcmdP);
if (status!=0) {
// local database error
return status; // not found
// prepare engine for sync (%%% new routine in 3.2.0.3, summarizing engInitForSyncOps() and
// switching to dssta_dataaccessstarted, i.e. loading sync set), but do in only once
if (!((*pos)->testState(dssta_syncsetready))) {
- // not yet started
- status = (*pos)->engInitForClientSync();
- if (status!=LOCERR_OK) {
+ // not yet started
+ status = (*pos)->engInitForClientSync();
+ if (status!=LOCERR_OK ) {
// failed
- AbortSession(status,true);
- return getAbortReasonStatus();
+ if (status!=LOCERR_DATASTORE_ABORT) {
+ AbortSession(status,true);
+ return getAbortReasonStatus();
+ }
}
}
// start or continue (which is largely nop, as continuing works via unfinished sync command)
// returns remaining time for request processing [seconds]
sInt32 TSyncAgent::RemainingRequestTime(void)
{
- // if no request timeout specified, use session timeout
- sInt32 t = fRequestMaxTime ? fRequestMaxTime : getSessionConfig()->fSessionTimeout;
- // calculate number of remaining seconds
- return
- t==0 ?
- 0x7FFFFFFF : // "infinite"
- t - (sInt32)((getSystemNowAs(TCTX_UTC)-getLastRequestStarted()) / (lineartime_t)secondToLinearTimeFactor);
+ if (IS_CLIENT) {
+ // clients don't process requests, so there's no limit
+ return 0x7FFFFFFF; // "infinite"
+ }
+ else {
+ // if no request timeout specified, use session timeout
+ sInt32 t = fRequestMaxTime ? fRequestMaxTime : getSessionConfig()->fSessionTimeout;
+ // calculate number of remaining seconds
+ return
+ t==0 ?
+ 0x7FFFFFFF : // "infinite"
+ t - (sInt32)((getSystemNowAs(TCTX_UTC)-getLastRequestStarted()) / (lineartime_t)secondToLinearTimeFactor);
+ }
} // TSyncAgent::RemainingRequestTime
#ifdef ENGINEINTERFACE_SUPPORT
if (fConfigP && !(fConfigP->fMan.empty()))
return fConfigP->fMan;
+ string s;
+ if (getConfigVar("custommanufacturer", s)) {
+ return s;
+ }
#endif
// if no string configured, return default
return CUST_SYNC_MAN;
// model (application name) of overall solution
-string TSyncAppBase::getModel(void) {
+string TSyncAppBase::getModel(void)
+{
#ifdef ENGINEINTERFACE_SUPPORT
if (fConfigP && !(fConfigP->fMod.empty()))
return fConfigP->fMod;
+ string s;
+ if (getConfigVar("custommodel", s)) {
+ return s;
+ }
#endif
// if no string configured, return default
return CUST_SYNC_MODEL;
// hardware version
-string TSyncAppBase::getHardwareVersion(void) {
+string TSyncAppBase::getHardwareVersion(void)
+{
+ string s;
#ifdef ENGINEINTERFACE_SUPPORT
if (fConfigP && !(fConfigP->fHwV.empty())) {
return fConfigP->fHwV;
}
+ if (getConfigVar("customhardwareversion", s)) {
+ return s;
+ }
#endif
- string s;
// if no string configured, return default
getPlatformString(pfs_device_name, s);
return s;
// firmware version (depends a lot on the context - OS version?)
-string TSyncAppBase::getFirmwareVersion(void) {
+string TSyncAppBase::getFirmwareVersion(void)
+{
+ string s;
#ifdef ENGINEINTERFACE_SUPPORT
if (fConfigP && !(fConfigP->fFwV.empty())) {
return fConfigP->fFwV;
}
+ if (getConfigVar("customfirmwareversion", s)) {
+ return s;
+ }
#endif
- string s;
// if no string configured, return default
getPlatformString(pfs_platformvers, s);
return s;
// hardware type (PDA, PC, ...)
-string TSyncAppBase::getDevTyp() {
+string TSyncAppBase::getDevTyp()
+{
#ifdef ENGINEINTERFACE_SUPPORT
+ string s;
if (fConfigP && !(fConfigP->fDevTyp.empty())) {
return fConfigP->fDevTyp;
}
+ if (getConfigVar("customdevicetype", s)) {
+ return s;
+ }
#endif
// if no string configured, return default
if (isServer())
} // TSyncAppBase::getDevTyp
+// device ID (can be customized using "customdeviceid" config variable)
+// Returns true if deviceID is guaranteed unique
+bool TSyncAppBase::getMyDeviceID(string &devid)
+{
+ #ifdef ENGINEINTERFACE_SUPPORT
+ if (getConfigVar("customdeviceid", devid)) {
+ return true; // custom device ID is assumed to be guaranteed unique
+ }
+ #endif
+ // use device ID as determined by platform adapters
+ return getLocalDeviceID(devid);
+} // TSyncAppBase::getMyDeviceID
+
+
+
#ifdef APP_CAN_EXPIRE
void TSyncAppBase::updateAppExpiry(void)
#else
#ifndef APP_CAN_EXPIRE
localstatus regsta = LOCERR_OK; // not registerable, not exprining - just run forever
- #ifdef RELEASE_VERSION
+ #ifndef NEVER_EXPIRES_IS_OK
#error "WARNING: Completely unlimited operation w/o license or expiry - is this intended??"
- #endif
+ #endif // not NEVER_EXPIRES_IS_OK
#else
localstatus regsta = LOCERR_BADREG; // not registerable, assume no license, must be eval which expires
- #endif
+ #endif // APP_CAN_EXPIRE
#endif
localstatus sta = regsta;
// check expiry (only if registration has not already defined one)
string getFirmwareVersion();
// - device type, only used for clients
string getDevTyp();
+ // - device ID, can be customized via "customdeviceid" config var
+ bool getMyDeviceID(string &devid);
// - hardwired information (cannot change, always identifying Synthesis engine and its version
cAppCharP getOEM(void) { return SYSYNC_OEM; } // hardwired, not configurable in target options
cAppCharP getSoftwareVersion(void) { return SYSYNC_FULL_VERSION_STRING; } // hardwired to real version number
fSessionP->AbortSession(412,false,statuscode); // other party's fault: incomplete command
return true; // done with command
}
+ else if (statuscode==418) {
+ POBJDEBUGPRINTFX(fSessionP,DBG_PROTO,("Status: 418: already existed on peer --> accept as ok"));
+ return true; // done with command
+ }
else if (statuscode<500) {
// originator exception (we sent some bad stuff)
POBJDEBUGPRINTFX(fSessionP,DBG_ERROR,("Status: %hd: originator exception",statuscode));
}
#ifdef SYDEBUG
// warn if error (don't treat slow sync status or conflict indication as errors)
- if (fStatusCode>=300 && fStatusCode!=508 && fStatusCode!=419) {
+ // - 418 = item already exits: sent by Funambol server when both client and
+ // and server have a new item which is considered identical by the server
+ // (must be really identical, minor difference will lead to a merged item
+ // which is sent back to the client without the 418). See Moblin Bugzilla #4599.
+ if (fStatusCode>=300 && fStatusCode!=508 && fStatusCode!=419 && fStatusCode!=418) {
PDEBUGPRINTFX(DBG_ERROR,(
"WARNING: RECEIVED NON-OK STATUS %hd for &html;<a name=\"SO_%ld_%ld\" href=\"#IO_%ld_%ld\">&html;command '%s'&html;</a>&html; (outgoing MsgID=%ld, CmdID=%ld)",
fStatusCode,
#ifndef MINIMAL_CODE
fRemoteDescName.erase();
#endif
+ fSubRulesList.clear(); // no included subrules
+ fSubRule = false; // normal rule by default
// - rules are final by default
fFinalRule = true;
// clear inherited
bool TRemoteRuleConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
{
// checking the elements
- // - identification of remote
- if (strucmp(aElementName,"manufacturer")==0)
+ // - identification of remote (irrelevant for subrules)
+ if (!fSubRule && strucmp(aElementName,"manufacturer")==0)
expectString(fManufacturer);
- else if (strucmp(aElementName,"model")==0)
+ else if (!fSubRule && strucmp(aElementName,"model")==0)
expectString(fModel);
- else if (strucmp(aElementName,"oem")==0)
+ else if (!fSubRule && strucmp(aElementName,"oem")==0)
expectString(fOem);
- else if (strucmp(aElementName,"firmware")==0)
+ else if (!fSubRule && strucmp(aElementName,"firmware")==0)
expectString(fFirmwareVers);
- else if (strucmp(aElementName,"software")==0)
+ else if (!fSubRule && strucmp(aElementName,"software")==0)
expectString(fSoftwareVers);
- else if (strucmp(aElementName,"hardware")==0)
+ else if (!fSubRule && strucmp(aElementName,"hardware")==0)
expectString(fHardwareVers);
- else if (strucmp(aElementName,"deviceid")==0)
+ else if (!fSubRule && strucmp(aElementName,"deviceid")==0)
expectString(fDevId);
- else if (strucmp(aElementName,"devicetype")==0)
+ else if (!fSubRule && strucmp(aElementName,"devicetype")==0)
expectString(fDevTyp);
// - options
else if (strucmp(aElementName,"legacymode")==0)
expectTristate(fForceUTC);
else if (strucmp(aElementName,"forcelocaltime")==0)
expectTristate(fForceLocaltime);
- /*
- // Some extra tweaking params for unstable devices and connections
- else if (strucmp(aElementName,"maxobjspersession")==0)
- expectUInt32(fMaxObjsPerSession); // max number of object add/deletes sent per session
- else if (strucmp(aElementName,"maxkbspersession")==0)
- expectUInt32(fMaxKBsPerSession); // max number of kilobytes content data sent per session
- else if (strucmp(aElementName,"maxmessagesize")==0)
- expectUInt32(fMaxMessageSize); // do not send larger messages than these (except if otherwise item cannot be sent)
- */
+ // inclusion of subrules
+ else if (strucmp(aElementName,"include")==0) {
+ // <include rule=""/>
+ expectEmpty();
+ const char* nam = getAttr(aAttributes,"rule");
+ if (!nam)
+ return fail("<include> must specify \"rule\"");
+ else {
+ // find rule
+ TRemoteRulesList::iterator pos;
+ TSessionConfig *scfgP = static_cast<TSessionConfig *>(getParentElement());
+ for(pos=scfgP->fRemoteRulesList.begin();pos!=scfgP->fRemoteRulesList.end();pos++) {
+ if (strucmp(nam,(*pos)->getName())==0) {
+ fSubRulesList.push_back(*pos);
+ return true; // done
+ }
+ }
+ return fail("rule '%s' for <include> not found (must be defined before included)",nam);
+ }
+ }
// rule script. Note that this is special, as it is NOT resolved in the config, but
// copied to the session first, as it might differ between sessions.
#ifdef SCRIPT_SUPPORT
{
// checking the elements
#ifndef NO_REMOTE_RULES
- if (strucmp(aElementName,"remoterule")==0) {
+ bool isSubRule = strucmp(aElementName,"subrule")==0;
+ if (strucmp(aElementName,"remoterule")==0 || isSubRule) {
// check for optional name attribute
const char* nam = getAttr(aAttributes,"name");
if (!nam) nam="unnamed";
// create rule
TRemoteRuleConfig *ruleP = new TRemoteRuleConfig(nam,this);
+ ruleP->fSubRule = isSubRule;
fRemoteRulesList.push_back(ruleP);
expectChildParsing(*ruleP);
}
getSyncAppBase()->getModel().c_str(), getSyncAppBase()->getManufacturer().c_str()
));
// show platform we're on
- string uri;
- getPlatformString(pfs_device_uri,uri);
+ string devid;
+ getSyncAppBase()->getMyDeviceID(devid);
PDEBUGPRINTFX(DBG_HOT,(
"---- Running on " SYSYNC_PLATFORM_NAME ", URI/deviceID='%s'",
- uri.c_str()
+ devid.c_str()
));
// show process and thread ID of the main session thread
#ifdef MULTI_THREAD_SUPPORT
#endif
// show platform details
string dname,vers;
+ // - as determined by engine itself
getPlatformString(pfs_device_name,dname);
getPlatformString(pfs_platformvers,vers);
PDEBUGPRINTFX(DBG_HOT,(
dname.c_str(),
vers.c_str()
));
+ // - as configured
+ PDEBUGPRINTFX(DBG_HOT,(
+ "---- Configured Hardware Version = '%s', Firmware Version = '%s'",
+ getSyncAppBase()->getHardwareVersion().c_str(),
+ getSyncAppBase()->getFirmwareVersion().c_str()
+ ));
// show time zone infos
lineartime_t tim;
string z,ts;
// - immediately abort SYNC command in progress
fLocalSyncDatastoreP = NULL;
#ifndef NO_REMOTE_RULES
- // - no remote rule applied
- fAppliedRemoteRuleP = NULL;
+ // - no remote rules applied
+ fActiveRemoteRules.clear();
#endif
// - set defaults for >=SyncML 1.1 features
fRemoteWantsNOC = false; // no, unless requested
// tristates!!
fEnumDefaultPropParams=getSessionConfig()->fEnumDefaultPropParams;
#ifdef SCRIPT_SUPPORT
- // - rule script is empty at start of session
- fRuleScript.erase();
// call session init script
if (!terminationCall && !fTerminated) {
TScriptContext::execute(
// check for aborted datastore
if (fLocalSyncDatastoreP->CheckAborted(aStatusCommand)) return false;
// check if we can process it now
+ // Note: request time limit is active in server only.
if (!fLocalSyncDatastoreP->engIsStarted(false) || RemainingRequestTime()<0) {
aQueueForLater=true; // re-execute later...
return true; // ...but otherwise ok
PDEBUGBLOCKDESC("RemoteRules","Checking for remote rules");
// get config for session
TSessionConfig *scP = getSessionConfig();
- // look if we have a matching rule for this device
+ // look if we have matching rule(s) for this device
TRemoteRulesList::iterator pos;
for(pos=scP->fRemoteRulesList.begin();pos!=scP->fRemoteRulesList.end();pos++) {
+ TRemoteRuleConfig *ruleP = *pos;
// compare with devinf (or test for default-rule if aDevInfP is NULL
if (
- ((*pos)->fManufacturer.empty() || (aDevInfP && strwildcmp(smlPCDataToCharP(aDevInfP->man),(*pos)->fManufacturer.c_str())==0)) &&
- ((*pos)->fModel.empty() || (aDevInfP && strwildcmp(smlPCDataToCharP(aDevInfP->mod),(*pos)->fModel.c_str())==0)) &&
- ((*pos)->fOem.empty() || (aDevInfP && strwildcmp(smlPCDataToCharP(aDevInfP->oem),(*pos)->fOem.c_str())==0)) &&
- ((*pos)->fFirmwareVers.empty() || (aDevInfP && (*pos)->fFirmwareVers==smlPCDataToCharP(aDevInfP->fwv))) &&
- ((*pos)->fSoftwareVers.empty() || (aDevInfP && (*pos)->fSoftwareVers==smlPCDataToCharP(aDevInfP->swv))) &&
- ((*pos)->fHardwareVers.empty() || (aDevInfP && (*pos)->fHardwareVers==smlPCDataToCharP(aDevInfP->hwv))) &&
- ((*pos)->fDevId.empty() || (aDevInfP && (*pos)->fDevId==smlPCDataToCharP(aDevInfP->devid))) &&
- ((*pos)->fDevTyp.empty() || (aDevInfP && (*pos)->fDevTyp==smlPCDataToCharP(aDevInfP->devtyp)))
+ !ruleP->fSubRule && // subrules never apply directly
+ (ruleP->fManufacturer.empty() || (aDevInfP && strwildcmp(smlPCDataToCharP(aDevInfP->man),ruleP->fManufacturer.c_str())==0)) &&
+ (ruleP->fModel.empty() || (aDevInfP && strwildcmp(smlPCDataToCharP(aDevInfP->mod),ruleP->fModel.c_str())==0)) &&
+ (ruleP->fOem.empty() || (aDevInfP && strwildcmp(smlPCDataToCharP(aDevInfP->oem),ruleP->fOem.c_str())==0)) &&
+ (ruleP->fFirmwareVers.empty() || (aDevInfP && ruleP->fFirmwareVers==smlPCDataToCharP(aDevInfP->fwv))) &&
+ (ruleP->fSoftwareVers.empty() || (aDevInfP && ruleP->fSoftwareVers==smlPCDataToCharP(aDevInfP->swv))) &&
+ (ruleP->fHardwareVers.empty() || (aDevInfP && ruleP->fHardwareVers==smlPCDataToCharP(aDevInfP->hwv))) &&
+ (ruleP->fDevId.empty() || (aDevInfP && ruleP->fDevId==smlPCDataToCharP(aDevInfP->devid))) &&
+ (ruleP->fDevTyp.empty() || (aDevInfP && ruleP->fDevTyp==smlPCDataToCharP(aDevInfP->devtyp)))
) {
- // found, apply rules
- TRemoteRuleConfig *ruleP = *pos;
- PDEBUGPRINTFX(DBG_HOT,("Found special rule '%s' for remote party, applying",ruleP->getName()));
- // set options
- // - only device specific
- fAppliedRemoteRuleP = ruleP; // save pointer to applied rule
- // - apply options that have a value
- if (ruleP->fLegacyMode>=0) fLegacyMode = ruleP->fLegacyMode;
- if (ruleP->fLenientMode>=0) fLenientMode = ruleP->fLenientMode;
- if (ruleP->fLimitedFieldLengths>=0) fLimitedRemoteFieldLengths = ruleP->fLimitedFieldLengths;
- if (ruleP->fDontSendEmptyProperties>=0) fDontSendEmptyProperties = ruleP->fDontSendEmptyProperties;
- if (ruleP->fDoQuote8BitContent>=0) fDoQuote8BitContent = ruleP->fDoQuote8BitContent;
- if (ruleP->fDoNotFoldContent>=0) fDoNotFoldContent = ruleP->fDoNotFoldContent;
- if (ruleP->fNoReplaceInSlowsync>=0) fNoReplaceInSlowsync = ruleP->fNoReplaceInSlowsync;
- if (ruleP->fTreatRemoteTimeAsLocal>=0) fTreatRemoteTimeAsLocal = ruleP->fTreatRemoteTimeAsLocal;
- if (ruleP->fTreatRemoteTimeAsUTC>=0) fTreatRemoteTimeAsUTC = ruleP->fTreatRemoteTimeAsUTC;
- if (ruleP->fVCal10EnddatesSameDay>=0) fVCal10EnddatesSameDay = ruleP->fVCal10EnddatesSameDay;
- if (ruleP->fIgnoreDevInfMaxSize>=0) fIgnoreDevInfMaxSize = ruleP->fIgnoreDevInfMaxSize;
- if (ruleP->fIgnoreCTCap>=0) fIgnoreCTCap = ruleP->fIgnoreCTCap;
- if (ruleP->fDSPathInDevInf>=0) fDSPathInDevInf = ruleP->fDSPathInDevInf;
- if (ruleP->fDSCgiInDevInf>=0) fDSCgiInDevInf = ruleP->fDSCgiInDevInf;
- if (ruleP->fUpdateClientDuringSlowsync>=0) fUpdateClientDuringSlowsync = ruleP->fUpdateClientDuringSlowsync;
- if (ruleP->fUpdateServerDuringSlowsync>=0) fUpdateServerDuringSlowsync = ruleP->fUpdateServerDuringSlowsync;
- if (ruleP->fAllowMessageRetries>=0) fAllowMessageRetries = ruleP->fAllowMessageRetries;
- if (ruleP->fStrictExecOrdering>=0) fStrictExecOrdering = ruleP->fStrictExecOrdering;
- if (ruleP->fTreatCopyAsAdd>=0) fTreatCopyAsAdd = ruleP->fTreatCopyAsAdd;
- if (ruleP->fCompleteFromClientOnly>=0) fCompleteFromClientOnly = ruleP->fCompleteFromClientOnly;
- if (ruleP->fRequestMaxTime>=0) fRequestMaxTime = ruleP->fRequestMaxTime;
- if (ruleP->fDefaultOutCharset!=chs_unknown) fDefaultOutCharset = ruleP->fDefaultOutCharset;
- if (ruleP->fDefaultInCharset!=chs_unknown) fDefaultInCharset = ruleP->fDefaultInCharset;
- // - possibly override decisions that are otherwise made by session
- // Note: this is not a single option because we had this before rule options were tristates.
- if (ruleP->fForceUTC>0) fRemoteCanHandleUTC=true;
- if (ruleP->fForceLocaltime>0) fRemoteCanHandleUTC=false;
- // - install rule script
- #ifdef SCRIPT_SUPPORT
- if (!ruleP->fRuleScriptTemplate.empty()) fRuleScript = (*pos)->fRuleScriptTemplate;
- #endif
- // - descriptive name for the device (for log)
- #ifndef MINIMAL_CODE
- if (!ruleP->fRemoteDescName.empty()) fRemoteDescName = (*pos)->fRemoteDescName;
- #endif
- // - test for rejection
- if (ruleP->fRejectStatusCode!=DONT_REJECT) {
- // reject operation with this device
- sta = (*pos)->fRejectStatusCode;
- PDEBUGPRINTFX(DBG_ERROR,("remote party rejected by configured 'remoterule', status=%hd",sta));
- AbortSession(sta,true);
- return sta;
- }
- // done only if this rule is final
+ // found matching rule
+ PDEBUGPRINTFX(DBG_HOT,("Found <remoterule> '%s' matching for this peer",ruleP->getName()));
+ // remember it
+ fActiveRemoteRules.push_back(ruleP);
+ // add included subrules
+ TRemoteRulesList::iterator spos;
+ for(spos=ruleP->fSubRulesList.begin();spos!=ruleP->fSubRulesList.end();spos++) {
+ fActiveRemoteRules.push_back(*spos);
+ PDEBUGPRINTFX(DBG_HOT,("- rule also activates sub-rule '%s'",(*spos)->getName()));
+ }
+ // if this rule is final, don't check for further matches
if (ruleP->fFinalRule) break;
+ }
+ }
+ // process activated rules and subrules
+ for(pos=fActiveRemoteRules.begin();pos!=fActiveRemoteRules.end();pos++) {
+ // activate this rule
+ TRemoteRuleConfig *ruleP = *pos;
+ // - apply options that have a value
+ if (ruleP->fLegacyMode>=0) fLegacyMode = ruleP->fLegacyMode;
+ if (ruleP->fLenientMode>=0) fLenientMode = ruleP->fLenientMode;
+ if (ruleP->fLimitedFieldLengths>=0) fLimitedRemoteFieldLengths = ruleP->fLimitedFieldLengths;
+ if (ruleP->fDontSendEmptyProperties>=0) fDontSendEmptyProperties = ruleP->fDontSendEmptyProperties;
+ if (ruleP->fDoQuote8BitContent>=0) fDoQuote8BitContent = ruleP->fDoQuote8BitContent;
+ if (ruleP->fDoNotFoldContent>=0) fDoNotFoldContent = ruleP->fDoNotFoldContent;
+ if (ruleP->fNoReplaceInSlowsync>=0) fNoReplaceInSlowsync = ruleP->fNoReplaceInSlowsync;
+ if (ruleP->fTreatRemoteTimeAsLocal>=0) fTreatRemoteTimeAsLocal = ruleP->fTreatRemoteTimeAsLocal;
+ if (ruleP->fTreatRemoteTimeAsUTC>=0) fTreatRemoteTimeAsUTC = ruleP->fTreatRemoteTimeAsUTC;
+ if (ruleP->fVCal10EnddatesSameDay>=0) fVCal10EnddatesSameDay = ruleP->fVCal10EnddatesSameDay;
+ if (ruleP->fIgnoreDevInfMaxSize>=0) fIgnoreDevInfMaxSize = ruleP->fIgnoreDevInfMaxSize;
+ if (ruleP->fIgnoreCTCap>=0) fIgnoreCTCap = ruleP->fIgnoreCTCap;
+ if (ruleP->fDSPathInDevInf>=0) fDSPathInDevInf = ruleP->fDSPathInDevInf;
+ if (ruleP->fDSCgiInDevInf>=0) fDSCgiInDevInf = ruleP->fDSCgiInDevInf;
+ if (ruleP->fUpdateClientDuringSlowsync>=0) fUpdateClientDuringSlowsync = ruleP->fUpdateClientDuringSlowsync;
+ if (ruleP->fUpdateServerDuringSlowsync>=0) fUpdateServerDuringSlowsync = ruleP->fUpdateServerDuringSlowsync;
+ if (ruleP->fAllowMessageRetries>=0) fAllowMessageRetries = ruleP->fAllowMessageRetries;
+ if (ruleP->fStrictExecOrdering>=0) fStrictExecOrdering = ruleP->fStrictExecOrdering;
+ if (ruleP->fTreatCopyAsAdd>=0) fTreatCopyAsAdd = ruleP->fTreatCopyAsAdd;
+ if (ruleP->fCompleteFromClientOnly>=0) fCompleteFromClientOnly = ruleP->fCompleteFromClientOnly;
+ if (ruleP->fRequestMaxTime>=0) fRequestMaxTime = ruleP->fRequestMaxTime;
+ if (ruleP->fDefaultOutCharset!=chs_unknown) fDefaultOutCharset = ruleP->fDefaultOutCharset;
+ if (ruleP->fDefaultInCharset!=chs_unknown) fDefaultInCharset = ruleP->fDefaultInCharset;
+ // - possibly override decisions that are otherwise made by session
+ // Note: this is not a single option because we had this before rule options were tristates.
+ if (ruleP->fForceUTC>0) fRemoteCanHandleUTC=true;
+ if (ruleP->fForceLocaltime>0) fRemoteCanHandleUTC=false;
+ // - descriptive name for the device (for log)
+ #ifndef MINIMAL_CODE
+ if (!ruleP->fRemoteDescName.empty()) fRemoteDescName = ruleP->fRemoteDescName;
+ #endif
+ // - test for rejection
+ if (ruleP->fRejectStatusCode!=DONT_REJECT) {
+ // reject operation with this device
+ sta = ruleP->fRejectStatusCode;
+ PDEBUGPRINTFX(DBG_ERROR,("remote party rejected by <remoterule> '%s', status=%hd",ruleP->getName(),sta));
+ AbortSession(sta,true);
+ return sta;
}
- } // for
- // - resolve and execute rule script
- #ifdef SCRIPT_SUPPORT
- if (!fRuleScript.empty()) {
- // resolve variable references
- TScriptContext::linkIntoContext(fRuleScript,fSessionScriptContextP,this);
- // execute now
- PDEBUGPRINTFX(DBG_HOT,("Executing rulescript."));
- TScriptContext::execute(
- fSessionScriptContextP,
- fRuleScript,
- NULL, // context's function table
- NULL // datastore pointer needed for context
- );
- }
- #endif // SCRIPT_SUPPORT
+ // - execute rule script
+ #ifdef SCRIPT_SUPPORT
+ if (!ruleP->fRuleScriptTemplate.empty()) {
+ // copy from template
+ string ruleScript = ruleP->fRuleScriptTemplate;
+ // resolve variable references
+ TScriptContext::linkIntoContext(ruleScript,fSessionScriptContextP,this);
+ // execute now
+ PDEBUGPRINTFX(DBG_HOT,("Executing rulescript for rule '%s'",ruleP->getName()));
+ TScriptContext::execute(
+ fSessionScriptContextP,
+ ruleScript,
+ NULL, // context's function table
+ NULL // datastore pointer needed for context
+ );
+ }
+ #endif
+ } // for all activated rules
PDEBUGENDBLOCK("RemoteRules");
#endif // NO_REMOTE_RULES
// Final adjustments
#ifndef NO_REMOTE_RULES
- if (!fAppliedRemoteRuleP)
+ if (fActiveRemoteRules.empty())
#endif
{
// no remote rule (none found or mechanism excluded by NO_REMOTE_RULES)
}
}
// show summary
- PDEBUGPRINTFX(DBG_HOT+DBG_REMOTEINFO,("Summary of all behaviour options (possibly set by remote rule)"));
+ PDEBUGPRINTFX(DBG_HOT+DBG_REMOTEINFO,("Summary of all behaviour options (possibly modified by remote rule(s))"));
#ifndef MINIMAL_CODE
PDEBUGPRINTFX(DBG_HOT+DBG_REMOTEINFO,("- Remote Description : %s",fRemoteDescName.c_str()));
#endif
} // TSyncSession::checkRemoteSpecifics
+#ifndef NO_REMOTE_RULES
+
+// check if given rule (by name, or if aRuleName=NULL by rule pointer) is active
+bool TSyncSession::isActiveRule(cAppCharP aRuleName, TRemoteRuleConfig *aRuleP)
+{
+ TRemoteRulesList::iterator pos;
+ for(pos=fActiveRemoteRules.begin();pos!=fActiveRemoteRules.end();pos++) {
+ if (
+ (aRuleName==NULL && (*pos)==aRuleP) || // match by pointer...
+ (strucmp(aRuleName,(*pos)->getName())==0) // ...or name
+ )
+ return true;
+ }
+ // no match
+ return false;
+} // TSyncSession::isActiveRule
+
+#endif // NO_REMOTE_RULES
+
// access to config
TSessionConfig *TSyncSession::getSessionConfig(void)
#ifndef NO_REMOTE_RULES
+class TRemoteRuleConfig; // forward
+
+typedef std::list<TRemoteRuleConfig *> TRemoteRulesList;
+
// remote party special rule
class TRemoteRuleConfig: public TConfigElement
{
TCharSets fDefaultInCharset; // default charset for input interpretation
TSyError fRejectStatusCode; // if >=0, attempt to connect will always be rejected with given status code
sInt8 fForceUTC; // force sending time in UTC (overrides SyncML 1.1 <utc/> devInf flag)
- sInt8 fForceLocaltime; // force sending time in localtime (overrides SyncML 1.1 <utc/> devInf flag)
+ sInt8 fForceLocaltime; // force sending time in localtime (overrides SyncML 1.1 <utc/> devInf flag)
#ifndef MINIMAL_CODE
string fRemoteDescName; // descriptive name of remote
#endif
#ifdef SCRIPT_SUPPORT
string fRuleScriptTemplate; // template for rule script
#endif
+ // list of subrules to activate
+ TRemoteRulesList fSubRulesList;
// flag if this is a final rule (if matches, no more rules will be checked)
bool fFinalRule;
+ // flag if this is a subrule (cannot match by itself)
+ bool fSubRule;
protected:
// check config elements
#ifndef HARDCODED_CONFIG
}; // TRemoteRuleConfig
-typedef std::list<TRemoteRuleConfig *> TRemoteRulesList;
#endif // NO_REMOTE_RULES
TCharSets fDefaultOutCharset; // default charset for output generation
TCharSets fDefaultInCharset; // default charset for input interpretation
#ifndef NO_REMOTE_RULES
- TRemoteRuleConfig *fAppliedRemoteRuleP; // applied remote rule
+ bool isActiveRule(cAppCharP aRuleName, TRemoteRuleConfig *aRuleP=NULL); // check if given rule (by name, or if aRuleName=NULL by rule pointer) is active
+ TRemoteRulesList fActiveRemoteRules; // list of remote rules currently active in this session
#endif
// legacy mode
bool fLegacyMode; // if set, remote will see the types marked preferred="legacy" in devInf as preferred types, not the regular preferred ones
#ifdef SCRIPT_SUPPORT
// Session level script context
TScriptContext *fSessionScriptContextP;
- // Active RemoteRule's scipt. Note that this is copied from the config
- // as it might differ from session to session (and can't be resolved in
- // the config globally)
- string fRuleScript; // rule script, copied from active RemoteRule
#endif
// Session options
bool fReadOnly;
#define SYSER_EXTRA_ID_GOOSYNC 10 // Toffa.com Goosync special version
#define SYSER_EXTRA_ID_FONELINK 11 // novamedia FoneLink special version
-
+#define SYSER_EXTRA_ID_SOOCIAL 12 // soocial.com special version
// product codes
tctx_tz_Atlantic, // -4 Atlantik (Kanada)
tctx_tz_Atlantic_2006, // -4 Atlantik (Kanada)
tctx_tz_Atlantic_2007, // -4 Atlantik (Kanada)
+ tctx_tz_ART_ARST, // -3 Buenos Aires
+ tctx_tz_ART_ARST_2006, // -3 Buenos Aires
+ tctx_tz_ART_ARST_2007, // -3 Buenos Aires
+ tctx_tz_ART_ARST_2008, // -3 Buenos Aires
+ tctx_tz_ART_ARST_2009, // -3 Buenos Aires
tctx_tz_AUS_Central, // 9.5 Darwin
tctx_tz_AUS_Eastern, // 10 Canberra, Melbourne, Sydney
tctx_tz_Azerbaijan, // 4 Baku
tctx_tz_Pacific_Mexico, // -8 Tijuana, Niederkalifornien (Mexiko)
tctx_tz_Romance, // 1 Bruessel, Kopenhagen, Madrid, Paris
tctx_tz_Russian, // 3 Moskau, St. Petersburg, Wolgograd
- tctx_tz_SA_Eastern, // -3 Buenos Aires, Georgetown
+ tctx_tz_SA_Eastern, // -3 Buenos Aires, Georgetown (OLD)
tctx_tz_SA_Pacific, // -5 Bogota, Lima, Quito, Rio Branco
tctx_tz_SA_Western, // -4 Caracas, La Paz
tctx_tz_Samoa, // -11 Midway-Inseln, Samoa
{ "Atlantic", "America/Halifax", -240, 60, " ", "", { 3, 0,2, 2,0 }, { 11, 0,1, 2,0 } }, // -4
{ "Atlantic", "America/Halifax", -240, 60, " ","2006", { 4, 0,1, 2,0 }, { 10, 0,5, 2,0 } }, // -4
{ "Atlantic", "America/Halifax", -240, 60, " ","2007", { 3, 0,2, 2,0 }, { 11, 0,1, 2,0 } }, // -4
+ { "ART/ARST", "America/Buenos_Aires", -180, 60, " ", "", { 0, 0,0, 0,0 }, { 0, 0,0, 0,0 } }, // -3
+ { "ART/ARST", "America/Buenos_Aires", -180, 60, " ","2006", { 0, 0,0, 0,0 }, { 0, 0,0, 0,0 } }, // -3
+ { "ART/ARST", "America/Buenos_Aires", -180, 60, " ","2007", { 12,-1,29,23,59}, { 1,-1,1, 0,0 } }, // -3
+ { "ART/ARST", "America/Buenos_Aires", -180, 60, " ","2008", { 10, 6,3,23,59}, { 3, 6,3,23,59} }, // -3
+ { "ART/ARST", "America/Buenos_Aires", -180, 60, " ","2009", { 10, 6,3,23,59}, { 3, 6,2,23,59} }, // -3
{ "AUS_Central", "Australia/Darwin", 570, 0, " ", "", { 0, 0,0, 0,0 }, { 0, 0,0, 0,0 } }, // 9.5
{ "AUS_Eastern", "Australia/Sydney", 600, 60, " ", "", { 10, 0,5, 2,0 }, { 3, 0,5, 3,0 } }, // 10
{ "Azerbaijan", "Asia/Baku", 240, 60, " ", "", { 3, 0,5, 4,0 }, { 10, 0,5, 5,0 } }, // 4
void Manufacturer( string &s, string name ) { AddCapa( s, CA_Manufacturer, name ); }
void Description ( string &s, string desc ) { AddCapa( s, CA_Description, desc ); }
void GuidStr ( string &s, string guidStr ) { AddCapa( s, CA_GUID, guidStr ); }
+void BuiltIn ( string &s, string plugin ) { AddCapa( s, CA_Plugin, plugin ); }
// Add global context <gContext> information to <s>
g= g->next;
} // while
-//printf( "ContextFound: %08X '%s'\n", g, dbName.c_str() );
return g!=NULL && g->ref!=NULL;
} // GlobContextFound
/*! Add a <guid> string to <s> */
void GuidStr ( string &s, string guidStr );
+/*! Add a <plugin> string to <s> */
+void BuiltIn ( string &s, string plugin );
+
/*! Add global context <gContext> information to <s> */
void GContext ( string &s, GlobContext* gContext );
#include "android/log.h"
#endif
-#define MyDB "SDK" /* local debug name */
-#define SDKversionMask 0xffff00ff /* Old mask for version comparison: Omit OS identifier */
-#define maxmsglen 1024 /* Maximum string length for callback string */
+#define MyDB "SDK" /* local debug name */
+#define Old_SDKversionMask 0xffff00ff /* Old mask for version comparison: Omit OS identifier */
+#define maxmsglen 1024 /* Maximum string length for callback string */
#define P 256
long v;
- #define SDK_VERSION_MAJOR 1 /* Release: V1.6.1, change this if you need troubles */
- #define SDK_VERSION_MINOR 6
- #define SDK_SUBVERSION 1
+ #define SDK_VERSION_MAJOR 1 /* Release: V1.7.0, change this if you need troubles */
+ #define SDK_VERSION_MINOR 7
+ #define SDK_SUBVERSION 0
/* allowed range for the local build number */
if (buildNumber< 0) buildNumber= 0;
bool Feature_Supported ( CVersion versionFeature, CVersion currentVersion )
{
CVersion v= currentVersion;
- if (v<VP_NewBuildNumber) v= v & SDKversionMask; /* avoid OS identifier comparison */
+ if (v<VP_NewBuildNumber) v= v & Old_SDKversionMask; /* avoid OS identifier comparison */
return v>=versionFeature;
} /* FeatureSupported */
bool Feature_SupportedEq( CVersion versionFeature, CVersion currentVersion )
{
CVersion v= currentVersion;
- if (v<VP_NewBuildNumber) v= v & SDKversionMask; /* avoid OS identifier comparison */
+ if (v<VP_NewBuildNumber) v= v & Old_SDKversionMask; /* avoid OS identifier comparison */
return v==versionFeature;
} /* FeatureSupportedEq */
CVersion aPrgVersion,
uInt16 aDebugFlags)
{
- TSyError err= LOCERR_OK;
+ TSyError err= LOCERR_OK;
+
fEngineName = aEngineName;
fPrgVersion = aPrgVersion;
fDebugFlags = aDebugFlags;
#if defined SYSYNC_ENGINE || defined SYSYNC_ENGINE_TEST
+ uInt16 cbVersion= DB_Callback_Version; // use current by default
if (fCI==NULL) {
fCI = &fCIBuffer;
fCIisStatic = true;
}
- InitCallback_Exotic( fCI, DB_Callback_Version );
+ else {
+ cbVersion= fCI->callbackVersion; // the cbVersion from outside (ConnectEngineS)
+ } // if
+
+ InitCallback_Exotic( fCI, cbVersion ); // be aware that it could be an older version
fCI->thisBase= this; // get <this> later for callback calls
CB_Connect ( fCI );
#endif
LOCERR_BADURL = 20046,
/** server not found */
LOCERR_SRVNOTFOUND = 20047,
+ /**
+ * ABORTDATASTORE() parameter to flag the current datastore as bad
+ * without aborting the whole session. Exact reason for abort depends
+ * on caller of that macro.
+ */
+ LOCERR_DATASTORE_ABORT = 20048,
/** cURL error code */
LOCERR_CURL = 21000,
/*VP_Init 0x01000000 * V1.0.N.0 : Initial version */
/*VP_1st 0x01000002 * V1.0.N.2 : 1st delivered version */
/*VP_Session_Login 0x01000003 * V1.0.N.3 : VAR_String for Session_Login: this version only */
+/*VP_EngineVersionParam 0x01000004 * V1.0.N.4 : <engineVersion> param for "Module_PluginParams" */
+/*VP_CB_Version2 = 0x01000005 * V1.0.N.5 : Callback version >= 2 supported */
- /** V1.0.N.4 : <engineVersion> param for "Module_PluginParams" */
- VP_EngineVersionParam = 0x01000004,
- /** V1.0.N.5 : Callback version >= 2 supported */
- VP_CB_Version2 = 0x01000005,
/** V1.0.N.6 : With new function "DeleteBlob" */
VP_DeleteBlob = 0x01000006,
/** V1.0.N.7 : With new "scripting" function "AdaptItemData" */
VP_Tunnel = 0x01060000,
/** V1.6.1.X : Correct SetValue support */
VP_SetValue = 0x01060100,
- /** V1.6.1.X : Current version, use 'Plugin_Version()' */
- VP_CurrentVersion = 0x01060100,
+ /** V1.6.2.X : 64 bit Java BLOB signature */
+ VP_BLOB_JSignature = 0x01060200,
+/*VP_091221 0x01060200 * V1.6.2.X : Released 21-Dec-09 */
+ /** V1.7.0.X : Current version, use 'Plugin_Version()' */
+ VP_CurrentVersion = 0x01070000,
/** -------- : Bad/undefined version */
VP_BadVersion = 0xffffffff,
#define CA_JNI "JNI" /* Indicates, if plugin is based on JNI */
#define CA_CSHARP "C#" /* Indicates, if plugin is based on C# */
#define CA_GUID "GUID" /* GUID */
+#define CA_Plugin "PLUGIN" /* Built-In plugin name */
#define CA_GlobContext "GlobContext" /* The global context, if available */
#define CA_ADMIN_Info "ADMIN_Info" /* Get ADMIN info as <name><SP>"ADMIN" with 'CreateContext' */
/* (supported for V1.3.7 and higher) */
#define Plugin_UI "plugin_ui"
+
/* Compatibility to older versions */
-#define Plugin_Param_OLD "plugin_param_OLD"
#define Plugin_SE_Auth_OLD "plugin_sessionauth_OLD"
#define Plugin_DS_Data_OLD1 "plugin_datastore_OLD1"
#define Plugin_DS_Data_OLD2 "plugin_datastore_OLD2"
#define Plugin_DS_Admin_OLD "plugin_datastoreadmin_OLD"
-#define Plugin_DS_Blob_OLD "plugin_datablob_OLD"
+#define Plugin_DS_Blob_OLD1 "plugin_datablob_OLD1"
+#define Plugin_DS_Blob_OLD2 "plugin_datablob_OLD2"
DBG_PLUGIN_EXOT = 0x0004,
/** direct printf calls for test */
DBG_PLUGIN_DIRECT= 0x0008,
+ /** GetValue/SetValue debugging */
+ DBG_GET_SET_VALUE= 0x0010,
/** Default mask: all bits set */
DBG_PLUGIN_ALL = 0xffff,
};
--- /dev/null
+The sample configs contain common elements (datatypes, scripts, remote
+rules, debug settings) which are maintained as separate files in the
+corresponding directories. When modifying those common elements, run
+"update-samples.pl" in this directory to update the sample configs.
+
+The complete samples are under version control for several reasons:
+1. avoid dependency on Perl unless common elements need to be updated
+2. effect of changes on complete config show up in patches
+3. the file layout and unshared parts (<client> and <server>) are
+ determined by the sample configs
+
+The naming of common elements determines the order in which they get
+inserted. Files not ending in .xml are ignored. Elements that only
+apply to a client or server are stored in the corresponding sub
+directories, while the shared elements are in the
+"debug/scripting/datatypes/remoterules".
+
+It is a somewhat subjective choice which elements are stored in one
+file and which ones are split up. The three elements of a datatype
+definition (field list, profile, datatype) where split up because
+there might be multiple different profiles using the same field list
+and some users of these files might want to replace the default one.
--- /dev/null
+ <!-- list of internal fields representing vCard data -->
+ <fieldlist name="contacts">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="REV" type="timestamp" compare="never" age="yes"/>
+
+ <!-- Name elements -->
+ <field name="N_LAST" type="string" compare="always"/>
+ <field name="N_FIRST" type="string" compare="always"/>
+ <field name="N_MIDDLE" type="string" compare="always"/>
+ <field name="N_PREFIX" type="string" compare="conflict"/>
+ <field name="N_SUFFIX" type="string" compare="conflict"/>
+ <field name="NICKNAME" type="string" compare="conflict"/>
+ <field name="TITLE" type="string" compare="conflict" merge="fillempty"/>
+
+ <field name="FN" type="string" compare="conflict" merge="fillempty"/>
+
+ <!-- categories and classification -->
+ <field name="CATEGORIES" array="yes" type="string" compare="conflict"/>
+
+ <!-- organisation -->
+ <field name="ORG_NAME" type="string" compare="slowsync" merge="fillempty"/>
+ <field name="ORG_DIVISION" type="string" compare="conflict" merge="fillempty"/>
+
+ <!-- birthday -->
+ <field name="BDAY" type="date" compare="conflict" merge="fillempty"/>
+
+ <!-- telephone numbers -->
+ <field name="TEL" array="yes" type="telephone" compare="conflict"/>
+ <field name="TEL_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
+ <field name="TEL_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="TEL_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+
+ <!-- emails -->
+ <field name="EMAIL" array="yes" type="multiline" compare="conflict"/>
+ <field name="EMAIL_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
+ <field name="EMAIL_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="EMAIL_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+
+ <!-- web addresses -->
+ <field name="WEB" array="yes" type="url" compare="conflict"/>
+ <field name="WEB_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 -->
+ <field name="WEB_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="WEB_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+
+ <!-- home address -->
+ <field name="ADR_STREET" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_ADDTL" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_STREET_FLAGS" array="yes" type="integer" compare="conflict"/> <!-- offset 0 (from ADR_STREET_FLAGS) -->
+ <field name="ADR_STREET_LABEL" array="yes" type="string" compare="conflict"/> <!-- offset 1 -->
+ <field name="ADR_STREET_ID" array="yes" type="integer" compare="conflict"/> <!-- offset 2 -->
+ <field name="ADR_POBOX" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_CITY" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_REG" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_ZIP" array="yes" type="multiline" compare="conflict"/>
+ <field name="ADR_COUNTRY" array="yes" type="multiline" compare="conflict"/>
+
+ <!-- Note -->
+ <field name="NOTE" type="multiline" compare="conflict" merge="lines"/>
+
+ <!-- Photo -->
+ <field name="PHOTO" type="blob" compare="never" merge="fillempty"/>
+ <field name="PHOTO_TYPE" type="integer" compare="never" merge="fillempty"/>
+
+ </fieldlist>
--- /dev/null
+ <!-- vCard profile -->
+ <mimeprofile name="vCard" fieldlist="contacts">
+
+ <profile name="VCARD" nummandatory="0"> <!-- we allow records without "N" as Address book can store them -->
+ <property name="VERSION">
+ <value conversion="version"/>
+ </property>
+
+ <property onlyformode="standard" name="PRODID" mandatory="no">
+ <value conversion="prodid"/>
+ </property>
+
+ <property name="REV">
+ <value field="REV"/>
+ </property>
+
+ <property name="N" values="5" mandatory="yes"> <!-- Note: makes N parse and generate even if not in remote's CTCap -->
+ <value index="0" field="N_LAST"/>
+ <value index="1" field="N_FIRST"/>
+ <value index="2" field="N_MIDDLE"/>
+ <value index="3" field="N_PREFIX"/>
+ <value index="4" field="N_SUFFIX"/>
+ </property>
+
+ <property name="FN">
+ <value field="FN"/>
+ </property>
+
+ <property name="NICKNAME" onlyformode="standard">
+ <value field="NICKNAME"/>
+ </property>
+
+ <property name="TITLE">
+ <value field="TITLE"/>
+ </property>
+
+ <property name="CATEGORIES" values="list" valueseparator="," altvalueseparator=";" > <!-- non-standard, but 1:1 as in vCard 3.0 (NOT like in vCalendar 1.0, where separator is ";") -->
+ <value field="CATEGORIES"/>
+ <position field="CATEGORIES" repeat="array" increment="1" minshow="0"/>
+ </property>
+
+ <property name="ORG" values="2">
+ <value index="0" field="ORG_NAME"/>
+ <value index="1" field="ORG_DIVISION"/>
+ </property>
+
+ <property name="TEL">
+ <value field="TEL"/>
+ <position field="TEL" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="TEL_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+ <enum name="VOICE" value="B3"/>
+ <enum name="CELL" value="B4"/>
+ <enum name="FAX" value="B5"/>
+ <enum name="PAGER" value="B6"/>
+ <enum name="PREF" value="B7"/>
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="EMAIL">
+ <value field="EMAIL"/>
+ <position field="EMAIL" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="EMAIL_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+ <enum name="INTERNET" value="B3"/>
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="URL">
+ <value field="WEB"/>
+ <position field="WEB" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="WEB_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+ <enum name="PREF" value="B3"/>
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="ADR" values="7">
+ <value index="0" field="ADR_POBOX"/>
+ <value index="1" field="ADR_ADDTL"/>
+ <value index="2" field="ADR_STREET"/>
+ <value index="3" field="ADR_CITY"/>
+ <value index="4" field="ADR_REG"/>
+ <value index="5" field="ADR_ZIP"/>
+ <value index="6" field="ADR_COUNTRY"/>
+ <position field="ADR_POBOX" repeat="array" increment="1" minshow="1"/>
+ <parameter name="TYPE" default="yes" positional="no" show="yes">
+ <value field="ADR_STREET_FLAGS" conversion="multimix" combine=",">
+ <enum name="HOME" value="B0"/>
+ <enum name="WORK" value="B1"/>
+ <enum mode="ignore" value="B2"/> <!-- OTHER -->
+
+ <enum mode="prefix" name="X-CustomLabel-" value="1.L"/>
+ <enum mode="prefix" name="X-Synthesis-Ref" value="2.L"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="BDAY">
+ <value field="BDAY"/>
+ </property>
+
+ <property name="NOTE" filter="no">
+ <value field="NOTE"/>
+ </property>
+
+ <property name="PHOTO" filter="no">
+ <value field="PHOTO" conversion="BLOB_B64"/>
+ <parameter name="TYPE" default="no" show="yes">
+ <value field="PHOTO_TYPE">
+ <enum name="JPEG" value="0"/>
+ </value>
+ </parameter>
+ </property>
+
+ </profile>
+ </mimeprofile>
--- /dev/null
+
+
+ <!-- vCard 2.1 datatype, using vCard profile defined above -->
+ <datatype name="vCard21" basetype="vcard">
+ <version>2.1</version>
+ <use mimeprofile="vCard"/>
+ </datatype>
+
+ <!-- vCard 3.0 datatype, using vCard profile defined above -->
+ <datatype name="vCard30" basetype="vcard">
+ <version>3.0</version>
+ <use mimeprofile="vCard"/>
+ </datatype>
--- /dev/null
+ <!-- common field list for events and todos (both represented by vCalendar/iCalendar) -->
+ <fieldlist name="calendar">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="ISEVENT" type="integer" compare="always"/>
+
+ <field name="DMODIFIED" type="timestamp" compare="never" age="yes"/>
+ <field name="DCREATED" type="timestamp" compare="never"/>
+
+ <field name="DGENERATED" type="timestamp" compare="never"/>
+
+ <field name="UID" type="string" compare="never"/>
+
+ <field name="CATEGORIES" array="yes" type="string" compare="conflict" merge="fillempty"/>
+ <field name="CLASS" type="integer" compare="conflict" merge="fillempty"/>
+ <field name="TRANSP" type="integer" compare="conflict" merge="fillempty"/>
+
+ <field name="SUMMARY" type="multiline" compare="always"/>
+ <field name="DESCRIPTION" type="multiline" compare="slowsync" merge="lines"/>
+ <field name="LOCATION" type="multiline" compare="slowsync" merge="lines"/>
+
+ <!-- recurrence rule block, fields must be in that order, including
+ DTSTART as last field !! -->
+ <field name="RR_FREQ" type="string" compare="conflict"/>
+ <field name="RR_INTERVAL" type="integer" compare="conflict"/>
+ <field name="RR_FMASK" type="integer" compare="conflict"/>
+ <field name="RR_LMASK" type="integer" compare="conflict"/>
+ <field name="RR_END" type="timestamp" compare="conflict"/>
+
+ <!-- Note: DTSTART/DTEND are compared in the <comparescript>,
+ therefore compare is set no "never" here -->
+ <field name="DTSTART" type="timestamp" compare="never"/>
+ <field name="DTEND" type="timestamp" compare="never"/>
+ <field name="DURATION" type="timestamp" compare="never"/>
+ <field name="COMPLETED" type="timestamp" compare="never"/>
+ <field name="DUE" type="timestamp" compare="never"/>
+
+ <field name="GEO_LAT" type="string" compare="never"/>
+ <field name="GEO_LONG" type="string" compare="never"/>
+
+ <field name="PRIORITY" type="integer" compare="conflict"/>
+ <field name="STATUS" type="integer" compare="conflict" merge="fillempty"/>
+
+ <field name="ALARM_TIME" type="timestamp" compare="conflict"/>
+ <field name="ALARM_SNOOZE" type="string" compare="conflict"/>
+ <field name="ALARM_REPEAT" type="string" compare="conflict"/>
+ <field name="ALARM_MSG" type="string" compare="conflict"/>
+ <field name="ALARM_ACTION" type="string" compare="conflict"/>
+ <field name="ALARM_REL" type="integer" compare="never"/>
+
+ <!-- non-standard -->
+ <field name="PARENT_UID" type="string" compare="never"/>
+
+ <!-- for events -->
+ <field name="EXDATES" array="yes" type="timestamp" compare="never"/>
+
+ <field name="ORIGSTART" array="no" type="timestamp" compare="never"/>
+ <field name="SEQNO" array="no" type="integer" compare="never"/>
+
+ <field name="ATTENDEES" array="yes" type="string" compare="never"/>
+ <field name="ATTENDEE_CNS" array="yes" type="string" compare="never"/>
+ <field name="ATTENDEE_PARTSTATS" array="yes" type="integer" compare="never"/>
+ <field name="ORGANIZER" array="no" type="string" compare="never"/>
+ <field name="ORGANIZER_CN" array="no" type="string" compare="never"/>
+
+ </fieldlist>
--- /dev/null
+ <!-- vCalendar with VTODO and VEVENT variants -->
+ <mimeprofile name="vCalendar" fieldlist="calendar">
+
+ <vtimezonegenmode>current</vtimezonegenmode>
+ <tzidgenmode>olson</tzidgenmode>
+
+ <profile name="VCALENDAR" nummandatory="1">
+
+ <property name="VERSION" mandatory="yes">
+ <value conversion="version"/>
+ </property>
+
+ <property onlyformode="standard" name="PRODID" mandatory="no">
+ <value conversion="prodid"/>
+ </property>
+
+ <property onlyformode="old" name="TZ" filter="false" suppressempty="yes">
+ <value field="DTSTART" conversion="tz"/>
+ </property>
+
+ <property onlyformode="old" name="DAYLIGHT" mode="daylight" filter="false" suppressempty="yes">
+ <value field="DTSTART" conversion="daylight"/>
+ </property>
+
+ <property name="GEO" values="2" suppressempty="yes" onlyformode="old" valueseparator=",">
+ <!-- LON,LAT in vCalendar 1.0 -->
+ <value index="0" field="GEO_LAT"/>
+ <value index="1" field="GEO_LONG"/>
+ </property>
+
+ <subprofile onlyformode="standard" name="VTIMEZONE" mode="vtimezones"/>
+
+ <!-- sub-profile for tasks -->
+ <subprofile name="VTODO" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="0">
+
+ <property name="LAST-MODIFIED">
+ <value field="DMODIFIED"/>
+ </property>
+
+ <property name="DTSTAMP" suppressempty="yes" onlyformode="standard">
+ <value field="DGENERATED"/>
+ </property>
+
+ <property name="DCREATED" suppressempty="yes" onlyformode="old">
+ <value field="DCREATED"/>
+ </property>
+ <property name="CREATED" suppressempty="yes" onlyformode="standard">
+ <value field="DCREATED"/>
+ </property>
+
+ <property name="UID" suppressempty="yes">
+ <value field="UID"/>
+ </property>
+
+ <property name="SEQUENCE" suppressempty="yes">
+ <value field="SEQNO"/>
+ </property>
+
+ <property name="GEO" values="2" suppressempty="yes" onlyformode="standard" valueseparator=";">
+ <!-- LAT;LON in iCalendar 2.0 -->
+ <value index="0" field="GEO_LONG"/>
+ <value index="1" field="GEO_LAT"/>
+ </property>
+
+ <property onlyformode="standard" name="CATEGORIES" values="list" valueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property onlyformode="old" name="CATEGORIES" values="list" valueseparator=";" altvalueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property name="CLASS" suppressempty="yes">
+ <value field="CLASS">
+ <enum name="PUBLIC" value="0"/>
+ <enum name="PRIVATE" value="1"/>
+ <enum name="CONFIDENTIAL" value="2"/>
+ </value>
+ </property>
+
+ <property name="SUMMARY" mandatory="yes">
+ <value field="SUMMARY"/>
+ </property>
+
+ <property name="DESCRIPTION" mandatory="yes">
+ <value field="DESCRIPTION"/>
+ </property>
+
+ <property name="LOCATION" mandatory="no">
+ <value field="LOCATION"/>
+ </property>
+
+ <property name="DTSTART" suppressempty="yes" delayedparsing="1">
+ <value field="DTSTART" conversion="autodate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DTSTART" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DTSTART" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="COMPLETED" suppressempty="yes" delayedparsing="1">
+ <value field="COMPLETED" conversion="autoenddate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="COMPLETED" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="COMPLETED" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="DUE" suppressempty="yes" delayedparsing="1">
+ <value field="DUE" conversion="autodate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DUE" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DUE" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="PRIORITY" suppressempty="yes">
+ <value field="PRIORITY"/>
+ </property>
+
+ <property name="STATUS" onlyformode="standard" suppressempty="yes">
+ <value field="STATUS" conversion="emptyonly">
+ <enum name="COMPLETED" value="0"/>
+ <enum name="NEEDS-ACTION" value="1"/>
+ <enum name="IN-PROCESS" value="2"/>
+ <enum name="CANCELLED" value="3"/>
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="SENT" value="8"/>
+ <enum name="CONFIRMED" value="9"/>
+ <enum name="DRAFT" value="10"/>
+ <enum name="FINAL" value="11"/>
+ </value>
+ </property>
+
+ <property name="STATUS" onlyformode="old" suppressempty="yes">
+ <value field="STATUS" conversion="emptyonly">
+ <enum name="COMPLETED" value="0"/>
+ <enum name="NEEDS ACTION" value="1"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="IN PROCESS" value="2"/>
+ <enum name="CANCELLED" value="3"/>
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="SENT" value="8"/>
+ <enum name="CONFIRMED" value="9"/>
+ <enum name="DRAFT" value="10"/>
+ <enum name="FINAL" value="11"/>
+ </value>
+ </property>
+
+
+ <!-- AALARM and DALARM both use the same fields -->
+ <property name="AALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+ <property name="DALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+
+ <subprofile onlyformode="standard" name="VALARM" nummandatory="1" field="ALARM_TIME">
+ <property name="TRIGGER" suppressempty="no" mandatory="yes">
+ <value field="ALARM_TIME"/>
+ <parameter name="VALUE" default="no" show="yes">
+ <value field="ALARM_TIME" conversion="FULLVALUETYPE"/>
+ </parameter>
+ <parameter name="RELATED" default="no" show="yes">
+ <value field="ALARM_REL">
+ <enum mode="ignore" value="0"/>
+ <enum name="START" value="1"/>
+ <enum name="END" value="2"/>
+ </value>
+ </parameter>
+ </property>
+ <property name="ACTION" suppressempty="yes" mandatory="yes">
+ <value field="ALARM_ACTION"/>
+ </property>
+ <property name="DESCRIPTION" suppressempty="yes">
+ <value field="ALARM_MSG"/>
+ </property>
+ <property name="REPEAT" suppressempty="yes">
+ <value field="ALARM_REPEAT"/>
+ </property>
+ </subprofile>
+
+ <property onlyformode="old" name="RELATED-TO" suppressempty="yes">
+ <value field="PARENT_UID"/>
+ </property>
+
+ <property onlyformode="standard" name="RELATED-TO" suppressempty="yes">
+ <value field="PARENT_UID"/>
+ <parameter onlyformode="standard" name="RELTYPE" default="no" positional="yes" show="yes">
+ <value>
+ <enum name="PARENT"/>
+ <enum mode="defaultvalue" name="other"/>
+ </value>
+ <position hasnot="other" shows="PARENT" field="PARENT_UID"/>
+ </parameter>
+ </property>
+
+ </subprofile>
+
+ <!-- sub-profile for event -->
+ <subprofile name="VEVENT" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="1">
+
+ <property name="LAST-MODIFIED">
+ <value field="DMODIFIED"/>
+ </property>
+
+ <property name="DTSTAMP" suppressempty="yes" onlyformode="standard">
+ <value field="DGENERATED"/>
+ </property>
+
+ <property name="DCREATED" suppressempty="yes" onlyformode="old">
+ <value field="DCREATED"/>
+ </property>
+ <property name="CREATED" suppressempty="yes" onlyformode="standard">
+ <value field="DCREATED"/>
+ </property>
+
+
+ <property name="UID" suppressempty="yes">
+ <value field="UID"/>
+ </property>
+
+ <property name="SEQUENCE" suppressempty="yes">
+ <value field="SEQNO"/>
+ </property>
+
+ <property name="GEO" values="2" suppressempty="yes" onlyformode="standard" valueseparator=";">
+ <!-- LAT;LON in iCalendar 2.0 -->
+ <value index="0" field="GEO_LONG"/>
+ <value index="1" field="GEO_LAT"/>
+ </property>
+
+ <property onlyformode="standard" name="CATEGORIES" values="list" valueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property onlyformode="old" name="CATEGORIES" values="list" valueseparator=";" altvalueseparator="," suppressempty="yes">
+ <value field="CATEGORIES" />
+ <position field="CATEGORIES" repeat="array" minshow="0"/>
+ </property>
+
+ <property name="CLASS" suppressempty="yes">
+ <value field="CLASS">
+ <enum name="PUBLIC" value="0"/>
+ <enum name="PRIVATE" value="1"/>
+ <enum name="CONFIDENTIAL" value="2"/>
+ </value>
+ </property>
+
+
+ <property name="TRANSP" suppressempty="yes" onlyformode="standard">
+ <value field="TRANSP">
+ <enum name="OPAQUE" value="0"/>
+ <enum name="TRANSPARENT" value="1"/>
+ <enum name="TENTATIVE" value="2"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->
+ <enum name="OUT_OF_OFFICE" value="3"/> <!-- according to Oracle de facto usage in vCalendar 1.0 -->
+ <enum mode="defaultvalue" value="0"/>
+ </value>
+ </property>
+ <property name="TRANSP" suppressempty="yes" onlyformode="old">
+ <value field="TRANSP"/> <!-- directly numeric in vCalendar 1.0 -->
+ </property>
+
+
+ <property name="PRIORITY" suppressempty="yes">
+ <value field="PRIORITY"/>
+ </property>
+
+ <property name="SUMMARY" mandatory="yes">
+ <value field="SUMMARY"/>
+ </property>
+
+ <property name="DESCRIPTION" mandatory="yes">
+ <value field="DESCRIPTION"/>
+ </property>
+
+ <property name="LOCATION" mandatory="no">
+ <value field="LOCATION"/>
+ </property>
+
+ <property name="DTSTART" suppressempty="yes" delayedparsing="1">
+ <value field="DTSTART" conversion="autodate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DTSTART" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DTSTART" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <!-- recurrence rule (with delayed parsing, as it is dependent on DTSTART) -->
+ <property name="RRULE" suppressempty="yes" delayedparsing="2">
+ <!-- Note: RR_FREQ is the beginning of a block of fields
+ suitable for the "rrule" conversion mode -->
+ <value field="RR_FREQ" conversion="rrule"/>
+ </property>
+
+ <!-- Symbian uses this, so it might make the client work with symbian-prepared servers better -->
+ <property name="X-RECURRENCE-ID" suppressempty="yes" onlyformode="old">
+ <value field="ORIGSTART" conversion="autodate"/>
+ </property>
+
+ <property name="RECURRENCE-ID" suppressempty="yes" onlyformode="standard" delayedparsing="1">
+ <value field="ORIGSTART" conversion="autodate"/>
+ <parameter name="TZID" default="no" show="yes">
+ <value field="ORIGSTART" conversion="TZID"/>
+ </parameter>
+ <parameter name="VALUE" default="no" show="yes">
+ <value field="ORIGSTART" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="EXDATE" values="list" suppressempty="yes" onlyformode="standard" delayedparsing="1" valueseparator="," altvalueseparator=";">
+ <value field="EXDATES"/>
+ <position field="EXDATES" repeat="array" increment="1" minshow="0"/>
+ <parameter name="TZID" default="no" show="yes">
+ <value field="EXDATES" conversion="TZID"/>
+ </parameter>
+ </property>
+
+ <property name="EXDATE" values="list" suppressempty="yes" onlyformode="old" delayedparsing="1" valueseparator=";" altvalueseparator=",">
+ <value field="EXDATES"/>
+ <position field="EXDATES" repeat="array" increment="1" minshow="0"/>
+ </property>
+
+
+ <property name="DTEND" suppressempty="yes" delayedparsing="1">
+ <value field="DTEND" conversion="autoenddate"/>
+ <parameter onlyformode="standard" name="TZID" default="no" show="yes">
+ <value field="DTEND" conversion="TZID"/>
+ </parameter>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="yes">
+ <value field="DTEND" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="DURATION" suppressempty="yes" delayedparsing="1" onlyformode="standard">
+ <value field="DURATION"/>
+ <parameter onlyformode="standard" name="VALUE" default="no" show="no">
+ <value field="DURATION" conversion="VALUETYPE"/>
+ </parameter>
+ </property>
+
+ <property name="ATTENDEE" suppressempty="yes" onlyformode="old">
+ <value field="ATTENDEES"/>
+ <parameter name="ROLE" default="no" positional="yes" show="yes">
+ <value>
+ <enum name="ORGANIZER"/>
+ </value>
+ <position has="ORGANIZER" field="ORGANIZER" overwriteempty="yes"/>
+ <position hasnot="ORGANIZER" field="ATTENDEES" repeat="array" increment="1" overwriteempty="yes"/>
+ </parameter>
+ <parameter name="STATUS" default="no" show="yes">
+ <value field="ATTENDEE_PARTSTATS">
+ <enum name="NEEDS ACTION" value="1"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="ATTENDEE" suppressempty="yes" onlyformode="standard">
+ <value field="ATTENDEES" conversion="mailto"/>
+ <position field="ATTENDEES" repeat="array" increment="1" minshow="0"/>
+ <parameter name="CN" default="no" show="yes" shownonempty="yes">
+ <value field="ATTENDEE_CNS"/>
+ </parameter>
+ <parameter name="PARTSTAT" default="no" show="yes">
+ <value field="ATTENDEE_PARTSTATS">
+ <enum name="NEEDS-ACTION" value="1"/>
+ <enum mode="defaultvalue" value="1"/> <!-- catch unknown, but also non-conformant NEEDS_ACTION -->
+ <enum name="ACCEPTED" value="4"/>
+ <enum name="DECLINED" value="7"/>
+ <enum name="TENTATIVE" value="5"/>
+ <enum name="DELEGATED" value="6"/>
+ </value>
+ </parameter>
+ </property>
+
+ <property name="ORGANIZER" suppressempty="yes" onlyformode="standard">
+ <value field="ORGANIZER" conversion="mailto"/>
+ <parameter name="CN" default="no" show="yes">
+ <value field="ORGANIZER_CN"/>
+ </parameter>
+ </property>
+
+
+ <!-- AALARM and DALARM both use the same fields -->
+ <property name="AALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+ <property name="DALARM" onlyformode="old" values="4" suppressempty="yes">
+ <value index="0" field="ALARM_TIME" conversion="emptyonly"/>
+ <value index="1" field="ALARM_SNOOZE" conversion="emptyonly"/>
+ <value index="2" field="ALARM_REPEAT" conversion="emptyonly"/>
+ <value index="3" field="ALARM_MSG" conversion="emptyonly"/>
+ </property>
+
+ <subprofile onlyformode="standard" name="VALARM" nummandatory="1" field="ALARM_TIME">
+ <property name="TRIGGER" suppressempty="no" mandatory="yes">
+ <value field="ALARM_TIME"/>
+ <parameter name="VALUE" default="no" show="yes">
+ <value field="ALARM_TIME" conversion="FULLVALUETYPE"/>
+ </parameter>
+ <parameter name="RELATED" default="no" show="yes">
+ <value field="ALARM_REL">
+ <enum mode="ignore" value="0"/>
+ <enum name="START" value="1"/>
+ <enum name="END" value="2"/>
+ </value>
+ </parameter>
+ </property>
+ <property name="ACTION" suppressempty="yes" mandatory="yes">
+ <value field="ALARM_ACTION"/>
+ </property>
+ <property name="DESCRIPTION" suppressempty="yes">
+ <value field="ALARM_MSG"/>
+ </property>
+ <property name="REPEAT" suppressempty="yes">
+ <value field="ALARM_REPEAT"/>
+ </property>
+ </subprofile>
+
+ </subprofile>
+
+ </profile>
+ </mimeprofile>
+
--- /dev/null
+ <!-- vCalendar 1.0 datatype, using vCalendar profile defined above -->
+ <datatype name="vCalendar10" basetype="vcalendar">
+ <version>1.0</version>
+ <use mimeprofile="vCalendar"/>
+
+ <incomingscript><![CDATA[
+ $VCALENDAR_INCOMING_SCRIPT
+ ]]></incomingscript>
+
+ <outgoingscript><![CDATA[
+ $VCALENDAR_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ </datatype>
+
+
+ <!-- iCalendar 2.0 datatype, using vCalendar profile defined above -->
+ <datatype name="iCalendar20" basetype="vcalendar">
+ <version>2.0</version>
+ <use mimeprofile="vCalendar"/>
+
+ <incomingscript><![CDATA[
+ $VCALENDAR_INCOMING_SCRIPT
+ ]]></incomingscript>
+
+ <outgoingscript><![CDATA[
+ $VCALENDAR_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ </datatype>
+
--- /dev/null
+ <!-- list of internal fields representing plain text note data -->
+ <fieldlist name="Note">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="SUBJECT" type="multiline" compare="always"/>
+ <field name="TEXT" type="multiline" compare="conflict" merge="lines"/>
+ </fieldlist>
+
--- /dev/null
+ <textprofile name="Note" fieldlist="Note">
+ <linemap field="SUBJECT">
+ <numlines>1</numlines>
+ <inheader>false</inheader>
+ <allowempty>true</allowempty>
+ <filterkeyword>SUBJECT</filterkeyword>
+ </linemap>
+ <linemap field="TEXT">
+ <numlines>0</numlines>
+ <inheader>false</inheader>
+ <allowempty>true</allowempty>
+ </linemap>
+ </textprofile>
+
--- /dev/null
+ <datatype name="note10" basetype="text">
+ <use profile="Note"/>
+ <typestring>text/plain</typestring>
+ <versionstring>1.0</versionstring>
+ </datatype>
+
+ <datatype name="note11" basetype="text">
+ <use profile="Note"/>
+ <typestring>text/plain</typestring>
+ <versionstring>1.1</versionstring>
+ </datatype>
+
--- /dev/null
+ <!-- list of internal fields representing vBookmark data -->
+ <fieldlist name="bookmarks">
+ <field name="REV" type="timestamp" compare="never" age="yes"/>
+ <field name="SYNCLVL" type="integer" compare="never"/>
+
+ <!-- Name -->
+ <field name="TITLE" type="string" compare="always"/>
+
+ <!-- categories and classification -->
+ <field name="CATEGORIES" type="string" compare="conflict" merge="fillempty"/>
+ <field name="CLASS" type="string" compare="conflict" merge="fillempty"/>
+
+ <!-- web addresses -->
+ <field name="URL" type="url" compare="slowsync" merge="fillempty"/>
+
+ <!-- Note -->
+ <field name="NOTE" type="multiline" compare="conflict" merge="lines"/>
+
+ </fieldlist>
+
--- /dev/null
+ <!-- vBookmark profile -->
+ <mimeprofile name="vBookmark" fieldlist="bookmarks">
+
+ <profile name="VBKM" nummandatory="0">
+ <property name="VERSION">
+ <value conversion="version"/>
+ </property>
+
+ <property name="X-LAST-MODIFIED">
+ <value field="REV"/>
+ </property>
+
+ <property name="TITLE">
+ <value field="TITLE"/>
+ </property>
+
+ <property name="URL">
+ <value field="URL"/>
+ </property>
+
+ <!-- non-standard properties -->
+
+ <!-- inherit CATEGORIES from vCard 3.0, i.e. comma separated -->
+ <property name="CATEGORIES" values="list" valueseparator="," altvalueseparator=";">
+ <value field="CATEGORIES" combine=","/>
+ </property>
+
+ <property name="CLASS" suppressempty="yes">
+ <value field="CLASS"/>
+ </property>
+
+ <property name="NOTE" filter="no">
+ <value field="NOTE"/>
+ </property>
+
+ </profile>
+ </mimeprofile>
+
--- /dev/null
+ <!-- vBookmark datatype, using vBookmark profile defined above -->
+ <datatype name="vBookmark10" basetype="mimedir">
+ <typestring>text/x-vbookmark</typestring>
+ <versionstring>1.0</versionstring>
+ <use profile="vBookmark"/>
+ </datatype>
+
--- /dev/null
+ <!-- list of internal fields representing email data -->
+ <fieldlist name="email">
+ <field name="SYNCLVL" type="integer" compare="never"/>
+ <field name="MODIFIED" type="timestamp" compare="never" age="yes"/>
+ <field name="SENDER" type="multiline" compare="always"/>
+ <field name="RECEIVER" type="multiline" compare="always"/>
+ <field name="CARBONCOPY" type="multiline" compare="always"/>
+ <field name="BLINDCARBONCOPY" type="multiline" compare="always"/>
+ <field name="REPLY_TO" type="multiline" compare="never"/>
+ <field name="SUBJECT" type="multiline" compare="always"/>
+ <field name="PRIORITY" type="integer" compare="never"/>
+ <field name="MAILDATE" type="timestamp" compare="never"/>
+ <field name="STATUS" type="string" compare="never"/>
+ <field name="FOLDER" type="string" compare="conflict"/>
+ <field name="ISREAD" type="string" compare="never"/>
+ <field name="LIMIT" type="integer" compare="never"/>
+ <field name="BODY" type="multiline" compare="never"/>
+ <field name="ATT_COUNT" type="integer" compare="never"/>
+ <field name="ATT_NAMES" array="yes" type="string" compare="never"/>
+ <field name="ATT_MIMETYPES" array="yes" type="string" compare="never"/>
+ <field name="ATT_SIZES" array="yes" type="integer" compare="never"/>
+ <field name="ATT_CONTENTS" array="yes" type="blob" compare="never"/>
+ </fieldlist>
+
--- /dev/null
+ <!-- this is the text profile used to generate and decode RFC2822/MIME-Multipart
+ email messages. -->
+ <textprofile name="rfc2822_email" fieldlist="email">
+
+ <mimemail>true</mimemail>
+ <!-- attachment configuration -->
+ <maxattachments>100</maxattachments>
+ <attachmentcountfield>ATT_COUNT</attachmentcountfield>
+ <attachmentmimetypesfield>ATT_MIMETYPES</attachmentmimetypesfield>
+ <attachmentsfield>ATT_CONTENTS</attachmentsfield>
+ <attachmentsizesfield>ATT_SIZES</attachmentsizesfield>
+ <attachmentnamesfield>ATT_NAMES</attachmentnamesfield>
+ <sizelimitfield>LIMIT</sizelimitfield>
+
+
+ <linemap field="SENDER">
+ <headertag>From:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>FROM</filterkeyword>
+ </linemap>
+
+ <linemap field="RECEIVER">
+ <headertag>To:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>TO</filterkeyword>
+ </linemap>
+
+ <linemap field="CARBONCOPY">
+ <headertag>Cc:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>CC</filterkeyword>
+ </linemap>
+
+ <linemap field="BLINDCARBONCOPY">
+ <headertag>Bcc:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>BCC</filterkeyword>
+ </linemap>
+
+ <linemap field="REPLY_TO">
+ <headertag>Reply-To:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="SUBJECT">
+ <headertag>Subject:</headertag>
+ <valuetype>rfc2047</valuetype>
+ <inheader>true</inheader>
+ <filterkeyword>SUBJECT</filterkeyword>
+ </linemap>
+
+ <linemap field="PRIORITY">
+ <headertag>X-Priority:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="MAILDATE">
+ <valuetype>date</valuetype>
+ <headertag>Date:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="STATUS">
+ <headertag>Status:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="FOLDER">
+ <headertag>X-Sync-Parent-Folder:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="ISREAD">
+ <headertag>X-Sync-Message-Read:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="MODIFIED">
+ <!-- note that this is a ISO8601 date -->
+ <headertag>X-Sync-Lastmodified:</headertag>
+ <inheader>true</inheader>
+ </linemap>
+
+ <linemap field="BODY">
+ <valuetype>body</valuetype>
+ <numlines>0</numlines>
+ <inheader>false</inheader>
+ <allowempty>true</allowempty>
+ </linemap>
+ </textprofile>
+
--- /dev/null
+ <!-- Note: This is a proprietary extension datatype for Synthesis AG Windows Mobile SyncML clients.
+ This format is a compressed form of the standard RFC2822 format. For one, the entire data
+ is compressed using the zip algorithm (<zippedbindata>), and secondly attachments are included
+ in binary form in the RFC2822 data stream rather than bandwidth wasting B64, adding a
+ "Content-Length:" header for each MIME part (<binaryparts>). -->
+
+ <datatype name="email_zipbin" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>application/x-zip-message</typestring> <!-- our own private zipped binary optimized format -->
+ <versionstring>1.1</versionstring>
+ <binaryparts>yes</binaryparts>
+ <zippedbindata>yes</zippedbindata>
+ <zipcompressionlevel>9</zipcompressionlevel> <!-- -1=default, 0=no compression, 1=fast & least effective ... 9=slow and most effective -->
+
+ <initscript><![CDATA[
+ $EMAIL_INIT_SCRIPT
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ $EMAIL_PROCESSITEM_SCRIPT
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ $EMAIL_MERGE_SCRIPT
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ $EMAIL_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ $EMAIL_FILTERINIT_SCRIPT
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ $EMAIL_FILTER_SCRIPT
+ ]]></filterscript>
+
+ </datatype>
+
--- /dev/null
+ <datatype name="email" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>text/message</typestring> <!-- this is P800-like -->
+ <versionstring>1.0</versionstring>
+
+ <initscript><![CDATA[
+ $EMAIL_INIT_SCRIPT
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ $EMAIL_PROCESSITEM_SCRIPT
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ $EMAIL_MERGE_SCRIPT
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ $EMAIL_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ $EMAIL_FILTERINIT_SCRIPT
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ $EMAIL_FILTER_SCRIPT
+ ]]></filterscript>
+
+ </datatype>
+
--- /dev/null
+ <datatype name="email_sonyericsson" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>message/rfc822</typestring> <!-- this is M600i/P990-like -->
+ <versionstring>1.0</versionstring>
+
+ <initscript><![CDATA[
+ $EMAIL_INIT_SCRIPT
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ $EMAIL_PROCESSITEM_SCRIPT
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ $EMAIL_MERGE_SCRIPT
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ $EMAIL_OUTGOING_SCRIPT
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ $EMAIL_FILTERINIT_SCRIPT
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ $EMAIL_FILTER_SCRIPT
+ ]]></filterscript>
+
+ </datatype>
+
--- /dev/null
+ <datatype name="email_nokia9500" basetype="text">
+ <use profile="rfc2822_email"/>
+ <typestring>message/x-rfc822</typestring> <!-- this is Nokia 9500/9300-like -->
+ <versionstring>1.0</versionstring>
+
+ <initscript><![CDATA[
+ INTEGER ITEMLIMIT;
+ // default limit is limit of session
+ ITEMLIMIT = SIZELIMIT();
+ ]]></initscript>
+
+ <processitemscript><![CDATA[
+ INTEGER n;
+
+ // For Nokia Email, we must derive folder ID from source LocURI
+ // which has form "./somestrangenumber/folder/itemid"
+ // where folder can be "Inbox" or "Outbox"
+ if (FIND(REMOTEID(),"Inbox",0)!=UNASSIGNED) {
+ FOLDER="INBOX";
+ }
+ else if (FIND(REMOTEID(),"Outbox",0)!=UNASSIGNED) {
+ FOLDER="OUTBOX";
+ }
+ // pre-process item
+ if (UPPERCASE(FOLDER)=="INBOX") {
+ // In any case, prevent adding to inbox (delete remote items instead)
+ PREVENTADD();
+ // server always wins for inbox
+ CONFLICTSTRATEGY("server-wins");
+ if (SLOWSYNC()) {
+ // also prevent modifications in server
+ IGNOREUPDATE();
+ }
+ else {
+ // normal sync items going to inbox from client need special treatment
+ if (SYNCOP()=="add" || SYNCOP()=="replace") {
+ // make sure that existing server item will conflict with this item
+ if (LIMIT!=EMPTY && (LIMIT<0 || LIMIT>SIZELIMIT())) {
+ // force conflict only if this is a reload
+ FORCECONFLICT();
+ }
+ // make sure we never overwrite a body in the inbox
+ BODY = UNASSIGNED;
+ // delete always wins over replace in inbox (to avoid adds to inbox)
+ DELETEWINS();
+ }
+ }
+ }
+ else if (UPPERCASE(FOLDER)=="OUTBOX") {
+ // never try to change something in outbox
+ IGNOREUPDATE();
+ if (SYNCOP()!="delete") {
+ // - date of mail is NOW, set it such that a correct date is written to the DB
+ MAILDATE = DBNOW();
+ // MAILDATE = (INTEGER)DBNOW() - TIMEUNITS(120); // %%% backdate it 2 mins to make sure it does not get retransmitted
+ // - echo item as delete (this causes that it is moved to the "sent" folder in the 9500)
+ ECHOITEM("delete");
+ }
+ CONFLICTSTRATEGY("client-wins");
+ }
+ else {
+ // Other folder
+ // - silently discard incoming item for other folder than the above
+ // except if it is a delete
+ if (SYNCOP()!="delete")
+ REJECTITEM(0);
+ }
+ ]]></processitemscript>
+
+
+ <mergescript><![CDATA[
+ // pre-process item
+ if (UPPERCASE(LOOSING.FOLDER)!="OUTBOX") {
+ // non-outbox (especially inbox) needs special merge to accomplish reload feature
+ // - loosing item is client's, winning is server's
+ if (LOOSING.LIMIT!=EMPTY) {
+ // loosing (remote) item specifies a new limit, override winning's default
+ WINNING.LIMIT=LOOSING.LIMIT;
+ SETWINNINGCHANGED(TRUE);
+ }
+ // make sure winning has right folder
+ WINNING.FOLDER=LOOSING.FOLDER;
+ // make sure a set read-flag gets propagated to server
+ if (LOOSING.ISREAD=="true") WINNING.ISREAD="true";
+ // merge other fields normally
+ MERGEFIELDS();
+ // make sure body does not get re-written to local DB even if merge would cause local update
+ LOOSING.BODY=UNASSIGNED;
+ }
+ else {
+ // normal merging in other folders
+ MERGEFIELDS();
+ }
+ ]]></mergescript>
+
+
+ <outgoingscript><![CDATA[
+ // we can only send to inbox or outbox
+ // - If we have no remote ID (=add command) prepare special Target item ID
+ // containing target folder.
+ if (REMOTEID()==EMPTY) {
+ if (UPPERCASE(FOLDER)=="INBOX") {
+ SETREMOTEID(REMOTEDBNAME()+"/Inbox/");
+ }
+ else if (UPPERCASE(FOLDER)=="OUTBOX") {
+ SETREMOTEID(REMOTEDBNAME()+"/Outbox/");
+ }
+ }
+ ]]></outgoingscript>
+
+ <filterinitscript><![CDATA[
+ // check if we need to filter
+ INTEGER NEEDFILTER;
+
+ NEEDFILTER =
+ !DBHANDLESOPTS() && // only if DB cannot handle it
+ (STARTDATE()!=EMPTY); // and only if a start date is set (end date not needed as there are never future emails today)
+ SETFILTERALL(NEEDFILTER);
+ RETURN NEEDFILTER;
+ ]]></filterinitscript>
+
+
+ <filterscript><![CDATA[
+ INTEGER PASSES;
+
+ // check if item passes filter
+ PASSES=FALSE;
+ // Filter out anything not for Inbox or Outbox
+ if (UPPERCASE(FOLDER)!="INBOX" && UPPERCASE(FOLDER)!="OUTBOX") RETURN FALSE;
+ // Emails pass if they have a MAILDATE on or later than start date
+ PASSES = MAILDATE>=STARTDATE();
+ RETURN PASSES;
+ ]]></filterscript>
+
+ </datatype>
--- /dev/null
+ <!-- path where logfiles are stored -->
+ <!-- <logpath platform="linux">/your/log/directory</logpath> -->
+ <logflushmode>buffered</logflushmode> <!-- buffered is fastest mode, but may loose data on process abort. Other options: "flush" (after every line) or "openclose" (safest, slowest, like in 2.x server) -->
+ <!-- per session log -->
+ <sessionlogs>yes</sessionlogs> <!-- by default, create a session log file for every sync session (might be disabled for special users/devices in scripts) -->
+ <!-- debug format options -->
+ <logformat>html</logformat> <!-- html is nicely colored and easily viewable with a web browser. Other options: "xml", "text" -->
+ <folding>auto</folding> <!-- dynamic folding of blocks enabled, automatically expanded or collapsed default. Other options: "none", "expanded", "collapsed" -->
+ <timestamp>yes</timestamp> <!-- show timestamps for structure elements in log -->
+ <timestampall>no</timestampall> <!-- don't show timestamp for every log line -->
+ <timedsessionlognames>yes</timedsessionlognames> <!-- session logs also have the session start timestamp in the filename - makes them more easily sortable -->
+ <!-- thread logging mode -->
+ <subthreadmode>separate</subthreadmode> <!-- write log info from subthreads into separate log files. Other options: "suppress" -->
+ <!-- basic debug level selection -->
+ <enable option="extended"/> <!-- "extended" is a good choice for start testing. For production, use "normal" or "minimal" -->
+ <!-- <enable option="normal"/> --> <!-- "normal" provides rich debug info, but still in reasonable size -->
+ <!-- <enable option="minimal"/> --> <!-- "minimal" just shows basic flow and error. Not suitable for debugging -->
+ <!-- <enable option="maximal"/> --> <!-- "maximal" can create VERY LARGE logs and cause HEAVY SLOWDOWN. Only for detail debugging -->
+ <!-- <enable option="all"/> --> <!-- "all" shows EVERYTHING possible, and way too much for any normal situation. For hardcore debugging ONLY! -->
+ <!-- additional debug info switches -->
+ <enable option="userdata"/> <!-- Make this <disable ...> if you don't want user data in the logs -->
+ <disable option="scripts"/> <!-- Make this <enable ...> to show script execution in logs -->
+ <disable option="match"/> <!-- Make this <enable ...> to show slow sync matching. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
+ <disable option="exotic"/> <!-- Make this <enable ...> to include very in-detail info. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
+ <!-- see manual for more debug info switches -->
+ <!-- global log options -->
+ <globallogs>no</globallogs> <!-- by default, do not log global session dispatching, creation etc. (not useful in multi-user operation) -->
+ <singlegloballog>no</singlegloballog> <!-- a new global log will be started for every start of the server/application -->
+ <!-- SyncML message dumping options -->
+ <msgdump>no</msgdump> <!-- do not dump syncml traffic 1:1 to files -->
+ <xmltranslate>no</xmltranslate> <!-- do not try to translate syncml traffic into XML (DO NOT SET THIS OPTION IN PRODUCTIVE SERVERS!) -->
--- /dev/null
+ <remoterule name="t39m">
+ <!-- Rule for Ericsson T39m client -->
+ <manufacturer>Ericsson</manufacturer>
+ <software>R1A</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>Ericsson T39m</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="t68">
+ <!-- Rule for Ericsson T68 client -->
+ <manufacturer>Ericsson</manufacturer>
+ <software>R1B</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>Ericsson T68</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="V3">
+ <!-- Rule for Motorola V3 -->
+ <manufacturer>Motorola*</manufacturer>
+ <model>V3</model>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <quote8bitcontent>yes</quote8bitcontent>
+ <nocontentfolding>yes</nocontentfolding>
+ <outputcharset>ANSI</outputcharset>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>Motorola V3</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="V3i">
+ <!-- Rule for Motorola V3i -->
+ <manufacturer>Motorola*</manufacturer>
+ <model>V3i</model>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <quote8bitcontent>yes</quote8bitcontent>
+ <nocontentfolding>yes</nocontentfolding>
+ <outputcharset>ANSI</outputcharset>
+ <descriptivename>Motorola V3i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6230">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6230</model>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6230</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9210">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9210</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 9210</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9210i">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9210i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 9210</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3220">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3220</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3220</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3230">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3230</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3230</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3600">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3600</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3600</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3620">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3620</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3620</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3650">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3650</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3650</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="3660">
+ <manufacturer>NOKIA</manufacturer>
+ <model>3660</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 3660</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6260">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6260</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6260</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6600">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6600</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6600</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6620">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6620</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6620</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6630">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6630</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6630</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="6670">
+ <manufacturer>NOKIA</manufacturer>
+ <model>6670</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 6670</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7250">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7250</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7250</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7250i">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7250i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7250i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7260">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7260</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7260</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7610">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7610</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7610</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="7650">
+ <manufacturer>NOKIA</manufacturer>
+ <model>7650</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia 7650</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="N-Gage">
+ <manufacturer>NOKIA</manufacturer>
+ <model>N-Gage</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia N-Gage</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="N-Gage QD">
+ <manufacturer>NOKIA</manufacturer>
+ <model>N-Gage QD</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Nokia N-Gage QD</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9300">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9300</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <treatasutc>yes</treatasutc> <!-- needs 2.1.1 or later server -->
+ <descriptivename>Nokia 9300</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="9500">
+ <manufacturer>NOKIA</manufacturer>
+ <model>9500</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <treatasutc>yes</treatasutc> <!-- needs 2.1.1 or later server -->
+ <descriptivename>Nokia 9500</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="E90">
+ <manufacturer>NOKIA</manufacturer>
+ <model>E90</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <ignoredevinfmaxsize>yes</ignoredevinfmaxsize>
+ <descriptivename>Nokia E90</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="X">
+ <manufacturer>Sendo</manufacturer>
+ <model>X</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>Sendo X</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SX1">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>SX1</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ ]]></rulescript>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <forcelocaltime>yes</forcelocaltime>
+ <!-- Note: SX1 crashes on contacts with empty properties -->
+ <noemptyproperties>yes</noemptyproperties>
+ <descriptivename>Siemens SX1</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="M55">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>M55</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens M55</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SL55">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>SL55</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens SL55</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="S55">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>S55</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens S55</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="S65">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>S65</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens S65</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SL65">
+ <manufacturer>SIEMENS</manufacturer>
+ <model>SL65</model>
+
+ <forcelocaltime>yes</forcelocaltime>
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>Siemens SL65</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="K700">
+ <!-- Rule for SonyEricsson K700 (aka SEMC Phone) client -->
+ <manufacturer>SonyEricsson</manufacturer>
+ <model>SEMC Phone</model>
+ <software>R3B</software>
+
+ <!-- is a 1.1 client and claims UTC support, but it seems not to work ok
+ <forcelocaltime>yes</forcelocaltime>
+ -->
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>SonyEricsson K700</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="T610/T630">
+ <!-- Rule for SonyEricsson T610/T630 client -->
+ <manufacturer>SonyEricsson</manufacturer>
+ <software>R2B</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <descriptivename>SonyEricsson T610/T630</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in M600i vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your M600i is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your M600i has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ M600i devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the M600i is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="M600i">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>M600i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson M600i</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P800 vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P800 is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P800 has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P800 devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P800 is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P800">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P800</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P800</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P900 vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P900 is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P900 has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P900 devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P900 is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P900">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P900</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P900</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P910 vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P910 is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P910 has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P910 devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P910 is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P910">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P910</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P910</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P910i vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P910i is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P910i has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P910i devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P910i is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P910i">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P910i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P910i</descriptivename>
+ </remoterule>
+
+
+ <!-- Due to a problem in P990i vCalendar implementation,
+ the device does not calculate time zones correctly
+ in all cases.
+ If your P990i is brand new, you need to specify
+ "calendar?/o(Z)" as database path instead of just
+ "calendar". If your P990i has already been synced
+ at least once via the cradle and the software
+ delivered with the device, you must omit the
+ "?/o(Z)" appendix and specify just "calendar" instead.
+ Please also note that the o(Z) option for never-synced
+ P990i devices only works if your server's config is
+ derived from a recent version of our sample config.
+ Otherwise, just make sure the P990i is synced once
+ in the cradle before using SyncML.
+ -->
--- /dev/null
+ <remoterule name="P990i">
+ <manufacturer>Sony Ericsson</manufacturer>
+ <model>P990i</model>
+
+ <rulescript><![CDATA[
+ // no dates before 1980
+ mindate=(TIMESTAMP)"19800101T000000Z";
+ // retransfer body when items are moved to sent box
+ retransfer_body=TRUE;
+ ]]></rulescript>
+
+ <treataslocaltime>no</treataslocaltime> <!-- can be set to yes to have /o(Z) mode (see comment above) as default, otherwise /o(z) is default -->
+ <forcelocaltime>yes</forcelocaltime>
+ <descriptivename>SonyEricsson P990i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="t68i">
+ <!-- Rule for SonyEricsson T68i client -->
+ <manufacturer>SonyEricsson</manufacturer>
+ <software>R2A</software>
+
+ <limitedfieldlengths>yes</limitedfieldlengths>
+ <inputcharset>ANSI</inputcharset>
+ <descriptivename>SonyEricsson T68i</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="Funambol_Outlook">
+ <!-- Rule for Funambol Outlook Sync Client -->
+ <model>Funambol Outlook Sync Client</model>
+
+ <lenientmode>yes</lenientmode> <!-- some status messages are missing at end of session -->
+ <descriptivename>Funambol Outlook Sync Client</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <remoterule name="SyncJe_Outlook">
+ <!-- Rule for NextHaus SyncJe Outlook Edition -->
+ <model>SyncJe Outlook Edition</model>
+
+ <ignorectcap>yes</ignorectcap> <!-- can do contact photo sync, but is missing in CTCap -->
+ <descriptivename>NextHaus SyncJe Outlook Client</descriptivename>
+ </remoterule>
+
+
--- /dev/null
+ <function><![CDATA[
+ // create a UID
+ string newuid() {
+ return "syuid" + NUMFORMAT(RANDOM(1000000),6,"0") + "." + (string)MILLISECONDS(NOW());
+ }
+ ]]></function>
+
+
--- /dev/null
+ <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
+
+ <macro name="VCALENDAR_INCOMING_SCRIPT"><![CDATA[
+ STRING MATCHES[];
+ STRING CAT,CN,EM;
+ INTEGER i;
+ TIMESTAMP ts;
+ // make sure we have all trailing and leading spaces eliminated
+ DESCRIPTION=NORMALIZED(DESCRIPTION);
+ SUMMARY=NORMALIZED(SUMMARY);
+ // eliminate description that is the same as summary
+ if (DESCRIPTION==SUMMARY) DESCRIPTION=EMPTY;
+ // calendar or todo
+ if (ISEVENT) {
+ // VEVENT
+ // - handle duration cases
+ if (ISDURATION(DURATION)) {
+ if (DTEND==EMPTY) DTEND = DTSTART + DURATION;
+ if (DTSTART==EMPTY) DTSTART = DTEND - DURATION;
+ }
+ // - detect alldays in vCalendar 1.0 (0:00-0:00 or 23:59 localtime)
+ i = ALLDAYCOUNT(DTSTART,DTEND,TRUE);
+ if (ITEMDATATYPE()=="vCalendar10" && i>0) {
+ // DTSTART and DTEND represent allday event, make them date-only values
+ // - convert start to user zone (or floating) so it represents midnight
+ DTSTART = CONVERTTOUSERZONE(DTSTART);
+ MAKEALLDAY(DTSTART,DTEND,i);
+ }
+ else {
+ // iCalendar 2.0 - only if DTSTART is a date-only value this really is an allday
+ if (ISDATEONLY(DTSTART)) {
+ // reshape to make sure we don't have invalid zero-duration alldays (old OCS 9 servers)
+ MAKEALLDAY(DTSTART,DTEND,i);
+ }
+ }
+ // - shape attendees (and make sure ATTENDEES[] is assigned even for empty email addresses)
+ i=0;
+ while(i<SIZE(ATTENDEES) || i<SIZE(ATTENDEE_CNS)) {
+ PARSEEMAILSPEC(ATTENDEES[i], CN, EM);
+ ATTENDEES[i] = EM; // pure email address
+ // in case we have no specific common name, use the one extracted from the email
+ // This catches the vCalendar 1.0 case and eventually ill-formed iCalendar 2.0 as well
+ if (ATTENDEE_CNS[i]==EMPTY)
+ ATTENDEE_CNS[i]=CN;
+ // default participation status to needs-action
+ if (ATTENDEE_PARTSTATS[i]==EMPTY)
+ ATTENDEE_PARTSTATS[i]=1; // 1=needs action
+ i=i+1;
+ }
+ // - shape organizer
+ PARSEEMAILSPEC(ORGANIZER, CN, EM);
+ ORGANIZER = EM; // pure email address
+ if (ORGANIZER_CN==EMPTY)
+ ORGANIZER_CN=CN;
+ }
+ else {
+ // VTODO
+ // - make sure we have at least a summary
+ if (SUMMARY==EMPTY) SUMMARY=DESCRIPTION; // use description if we don't have a summary
+ if (SUMMARY==EMPTY) SUMMARY="unnamed"; // set dummy summary if we still don't have one
+ // due shaping for non-iCalendar 2.0
+ if (ITEMDATATYPE()=="vCalendar10" && ALLDAYCOUNT(DUE,DUE,TRUE,TRUE)>0) {
+ DUE = DATEONLY(DUE);
+ }
+ }
+ // Common alarm handling
+ // - handle relative alarm time (as possible with VALARM TRIGGER)
+ if (ISDURATION(ALARM_TIME)) {
+ if (ALARM_REL==2)
+ ts = DTEND; // relative to end
+ else {
+ if (ISEVENT)
+ ts = DTSTART; // relative to start for events
+ else
+ ts = DUE; // relative to due for todos
+ }
+ // for now, make ALARM user(=system) zone in all cases
+ ALARM_TIME = CONVERTTOUSERZONE(POINTINTIME(ts),TRUE) + ALARM_TIME;
+ }
+ ]]></macro>
+
+
+ <macro name="VCALENDAR_OUTGOING_SCRIPT"><![CDATA[
+ // set UTC time of generation for iCalendar 2.0 DTSTAMP
+ DGENERATED = NOW();
+ // make sure we have all trailing and leading spaces eliminated
+ DESCRIPTION=NORMALIZED(DESCRIPTION);
+ SUMMARY=NORMALIZED(SUMMARY);
+ if (ISEVENT) {
+ // VEVENT
+ // - combine attendee email address and common name into single string for vCalendar 1.0
+ if (ITEMDATATYPE()=="vCalendar10") {
+ i=0;
+ while(i<SIZE(ATTENDEES)) {
+ ATTENDEES[i] = MAKEEMAILSPEC(ATTENDEE_CNS[i], ATTENDEES[i]);
+ i=i+1;
+ }
+ ORGANIZER = MAKEEMAILSPEC(ORGANIZER_CN, ORGANIZER);
+ }
+ }
+ else {
+ // VTODO
+ // - Nothing special so far
+ }
+ // make sure we have at least a summary
+ if (SUMMARY==EMPTY) SUMMARY=SUBSTR(DESCRIPTION,0,32); // derive from description
+ if (SUMMARY==EMPTY) SUMMARY="unnamed"; // in case description is empty as well
+ // do NOT send duration (some servers crash when doing so)
+ DURATION = UNASSIGNED;
+ // shape alarm
+ if (ALARM_TIME!=EMPTY) {
+ if (ITEMDATATYPE()=="iCalendar20") {
+ if (ALARM_ACTION==EMPTY) ALARM_ACTION = "AUDIO";
+ ALARM_TIME = CONVERTTOUSERZONE(ALARM_TIME,TRUE); // unfloat into user (system) zone, in case it is floating
+ ALARM_TIME = CONVERTTOZONE(ALARM_TIME,"UTC"); // must always be UTC by iCalendar 2.0 specs
+ // send as duration if we have non-empty non-date DTSTART
+ if (DTSTART!=EMPTY && !ISDATEONLY(DTSTART)) {
+ // make a duration (unfloat DTSTART into system zone in case it is floating first!)
+ ALARM_TIME = ALARM_TIME-CONVERTTOZONE(CONVERTTOUSERZONE(DTSTART,TRUE),"UTC");
+ ALARM_REL = 1; // relative to start
+ }
+ }
+ else {
+ if (ALARM_MSG==EMPTY) ALARM_MSG="alarm";
+ }
+ }
+ ]]></macro>
--- /dev/null
+ <looptimeout>5</looptimeout>
+
--- /dev/null
+ <!-- The following email handling scripts are defined as script MACROS because they
+ are used in multiple <datatype> definitions below. This avoids duplicating these
+ script's source code in the config file -->
+
+ <macro name="EMAIL_INIT_SCRIPT"><![CDATA[
+ INTEGER ITEMLIMIT;
+ // default limit is limit of session
+ ITEMLIMIT = SIZELIMIT();
+ ]]></macro>
+
+
+ <macro name="EMAIL_PROCESSITEM_SCRIPT"><![CDATA[
+ // pre-process item
+ if (UPPERCASE(FOLDER)=="INBOX") {
+ // In any case, prevent adding to inbox (delete remote items instead)
+ PREVENTADD();
+ // server always wins for inbox
+ CONFLICTSTRATEGY("server-wins");
+ if (SLOWSYNC()) {
+ // also prevent modifications in server
+ IGNOREUPDATE();
+ }
+ else {
+ // normal sync items going to inbox from client need special treatment
+ if (SYNCOP()=="add" || SYNCOP()=="replace") {
+ // make sure that existing server item will conflict with this item
+ if (LIMIT!=EMPTY && (LIMIT<0 || LIMIT>SIZELIMIT())) {
+ // force conflict only if this is a reload
+ FORCECONFLICT();
+ }
+ // make sure we never overwrite a body in the inbox
+ BODY = UNASSIGNED;
+ // delete always wins over replace in inbox (to avoid adds to inbox)
+ DELETEWINS();
+ }
+ }
+ }
+ else if (UPPERCASE(FOLDER)=="OUTBOX") {
+ // never try to change something in outbox
+ IGNOREUPDATE();
+ if (SYNCOP()!="delete") {
+ // - date of mail is NOW, set it such that a correct date is written to the DB
+ MAILDATE = DBNOW();
+ // MAILDATE = (INTEGER)DBNOW() - TIMEUNITS(120); // %%% backdate it 2 mins to make sure it does not get retransmitted
+ // - echo item as replace (to force-move it to the sent folder)
+ ECHOITEM("replace");
+ }
+ CONFLICTSTRATEGY("client-wins");
+ }
+ else if (UPPERCASE(FOLDER)=="SENT") {
+ // never try to change something in sent folder
+ IGNOREUPDATE();
+ // Server has precedence in case of conflicts
+ CONFLICTSTRATEGY("server-wins");
+ // Implement reload capability for sent items as well
+ if (SLOWSYNC()) {
+ // do not add new sent items to the server in slowsync
+ PREVENTADD(); // causes extra sent items on the client to be deleted
+ }
+ else {
+ // make sure that existing server item will conflict with this item
+ if (SYNCOP()=="replace") {
+ if (LIMIT!=EMPTY && (LIMIT<0 || LIMIT>SIZELIMIT())) {
+ // force conflict only if this is a reload
+ FORCECONFLICT();
+ REJECTITEM(200); // but do not process the item further
+ }
+ else {
+ // silently ignore other types of changes
+ REJECTITEM(200);
+ }
+ // make sure we never overwrite a body in the sent folder
+ BODY = UNASSIGNED;
+ }
+ }
+ }
+ else {
+ // Other folder
+ // - silently discard incoming item for other folder than the above
+ // except if it is a delete
+ if (SYNCOP()!="delete")
+ REJECTITEM(0);
+ }
+ ]]></macro>
+
+
+ <macro name="EMAIL_MERGE_SCRIPT"><![CDATA[
+ // pre-process item
+ if (UPPERCASE(LOOSING.FOLDER)!="OUTBOX") {
+ // non-outbox (especially inbox) needs special merge to accomplish reload feature
+ // - loosing item is client's, winning is server's
+ if (LOOSING.LIMIT!=EMPTY) {
+ // loosing (remote) item specifies a new limit, override winning's default
+ WINNING.LIMIT=LOOSING.LIMIT;
+ SETWINNINGCHANGED(TRUE);
+ }
+ // make sure winning has right folder
+ WINNING.FOLDER=LOOSING.FOLDER;
+ // make sure a set read-flag gets propagated to server
+ if (LOOSING.ISREAD=="true") WINNING.ISREAD="true";
+ // merge other fields normally
+ MERGEFIELDS();
+ // make sure body does not get re-written to local DB even if merge would cause local update
+ LOOSING.BODY=UNASSIGNED;
+ }
+ else {
+ // normal merging in other folders
+ MERGEFIELDS();
+ }
+ ]]></macro>
+
+ <macro name="EMAIL_OUTGOING_SCRIPT"><![CDATA[
+ // pre-process item
+ if (UPPERCASE(FOLDER)=="OUTBOX") {
+ // writing to outbox is always the ECHOITEM
+ // - cause item to move into "sent" folder
+ FOLDER = "sent";
+ if (!SESSIONVAR("retransfer_body")) {
+ // - prevent body retransfer, but not for dumb P800/P900/M600/P990 clients
+ BODY = UNASSIGNED; // prevent body transfer
+ ATT_COUNT = 0; // prevent attachment transfer
+ ATT_CONTENTS = UNASSIGNED;
+ // basically, this item is not limited (already complete on the client)
+ // even if contents are not sent
+ LIMIT = -1;
+ SETSIZELIMIT(-1);
+ }
+ }
+ else {
+ // outgoing item to any folder of of remote (inbox, sent...)
+ // - limit body to what is set in the LIMIT field
+ // %%% probably obsolete, as textitem will handle limit field automatically for >=V1.0.8.21
+ IF (LIMIT==EMPTY)
+ LIMIT = SIZELIMIT(); // if none set already, use default for this item (=default of datastore, if not SETSIZELIMIT() called before for this item generation)
+ }
+ // set limit for item generator
+ if (LIMIT!=EMPTY)
+ SETSIZELIMIT(LIMIT);
+ ]]></macro>
+
+
+ <macro name="EMAIL_FILTERINIT_SCRIPT"><![CDATA[
+ // check if we need to filter
+ INTEGER NEEDFILTER;
+
+ NEEDFILTER =
+ !DBHANDLESOPTS() && // only if DB cannot handle it
+ (STARTDATE()!=EMPTY); // and only if a start date is set (end date not needed as there are never future emails today)
+ SETFILTERALL(NEEDFILTER);
+ RETURN NEEDFILTER;
+ ]]></macro>
+
+
+ <macro name="EMAIL_FILTER_SCRIPT"><![CDATA[
+ INTEGER PASSES;
+
+ // check if item passes filter
+ PASSES=FALSE;
+ // Emails pass if they have a MAILDATE on or later than start date
+ PASSES = MAILDATE>=STARTDATE();
+ RETURN PASSES;
+ ]]></macro>
<sessionlogs>yes</sessionlogs> <!-- by default, create a session log file for every sync session (might be disabled for special users/devices in scripts) -->
<!-- debug format options -->
<logformat>html</logformat> <!-- html is nicely colored and easily viewable with a web browser. Other options: "xml", "text" -->
+ <folding>auto</folding> <!-- dynamic folding of blocks enabled, automatically expanded or collapsed default. Other options: "none", "expanded", "collapsed" -->
<timestamp>yes</timestamp> <!-- show timestamps for structure elements in log -->
<timestampall>no</timestampall> <!-- don't show timestamp for every log line -->
<timedsessionlognames>yes</timedsessionlognames> <!-- session logs also have the session start timestamp in the filename - makes them more easily sortable -->
<!-- additional debug info switches -->
<enable option="userdata"/> <!-- Make this <disable ...> if you don't want user data in the logs -->
<disable option="scripts"/> <!-- Make this <enable ...> to show script execution in logs -->
+ <disable option="match"/> <!-- Make this <enable ...> to show slow sync matching. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
<disable option="exotic"/> <!-- Make this <enable ...> to include very in-detail info. CAN PRODUCE ENORMOUS LOGS and HEAVILY IMPACT PERFORMANCE for large slow syncs - use with care! -->
<!-- see manual for more debug info switches -->
<!-- global log options -->
<!-- SyncML message dumping options -->
<msgdump>no</msgdump> <!-- do not dump syncml traffic 1:1 to files -->
<xmltranslate>no</xmltranslate> <!-- do not try to translate syncml traffic into XML (DO NOT SET THIS OPTION IN PRODUCTIVE SERVERS!) -->
+
</debug>
<transport type="xpt">
]]></function>
- <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
+ <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
<macro name="VCALENDAR_INCOMING_SCRIPT"><![CDATA[
STRING MATCHES[];
if (SUMMARY==EMPTY) SUMMARY="unnamed"; // set dummy summary if we still don't have one
// due shaping for non-iCalendar 2.0
if (ITEMDATATYPE()=="vCalendar10" && ALLDAYCOUNT(DUE,DUE,TRUE,TRUE)>0) {
- DUE = DATEONLY(DUE);
+ DUE = DATEONLY(DUE);
}
}
// Common alarm handling
<datatypes>
-
<!-- list of internal fields representing vCard data -->
<fieldlist name="contacts">
+ <field name="SYNCLVL" type="integer" compare="never"/>
<field name="REV" type="timestamp" compare="never" age="yes"/>
<!-- Name elements -->
<field name="PHOTO_TYPE" type="integer" compare="never" merge="fillempty"/>
</fieldlist>
-
<!-- vCard profile -->
<mimeprofile name="vCard" fieldlist="contacts">
</profile>
</mimeprofile>
+
<!-- vCard 2.1 datatype, using vCard profile defined above -->
<datatype name="vCard21" basetype="vcard">
<version>2.1</version>
<version>3.0</version>
<use mimeprofile="vCard"/>
</datatype>
-
-
<!-- common field list for events and todos (both represented by vCalendar/iCalendar) -->
<fieldlist name="calendar">
+ <field name="SYNCLVL" type="integer" compare="never"/>
<field name="ISEVENT" type="integer" compare="always"/>
<field name="DMODIFIED" type="timestamp" compare="never" age="yes"/>
<field name="ORGANIZER_CN" array="no" type="string" compare="never"/>
</fieldlist>
-
-
<!-- vCalendar with VTODO and VEVENT variants -->
<mimeprofile name="vCalendar" fieldlist="calendar">
<subprofile onlyformode="standard" name="VTIMEZONE" mode="vtimezones"/>
- <!-- sub-profile for todoz -->
+ <!-- sub-profile for tasks -->
<subprofile name="VTODO" nummandatory="1" showifselectedonly="yes" field="ISEVENT" value="0">
<property name="LAST-MODIFIED">
</profile>
</mimeprofile>
-
<!-- vCalendar 1.0 datatype, using vCalendar profile defined above -->
<datatype name="vCalendar10" basetype="vcalendar">
<version>1.0</version>
</datatype>
-
<!-- list of internal fields representing plain text note data -->
<fieldlist name="Note">
<field name="SYNCLVL" type="integer" compare="never"/>
<versionstring>1.1</versionstring>
</datatype>
-
<!-- list of internal fields representing vBookmark data -->
<fieldlist name="bookmarks">
<field name="REV" type="timestamp" compare="never" age="yes"/>
<!-- non-standard properties -->
- <property name="CATEGORIES">
- <value field="CATEGORIES"/>
+ <!-- inherit CATEGORIES from vCard 3.0, i.e. comma separated -->
+ <property name="CATEGORIES" values="list" valueseparator="," altvalueseparator=";">
+ <value field="CATEGORIES" combine=","/>
</property>
<property name="CLASS" suppressempty="yes">
<!-- SyncML message dumping options -->
<msgdump>no</msgdump> <!-- do not dump syncml traffic 1:1 to files -->
<xmltranslate>no</xmltranslate> <!-- do not try to translate syncml traffic into XML (DO NOT SET THIS OPTION IN PRODUCTIVE SERVERS!) -->
+
</debug>
<scripting>
- <!-- Global script function definitions -->
-
<function><![CDATA[
// create a UID
string newuid() {
]]></function>
- <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
+ <!-- define script macros for scripts that are used by both vCalendar 1.0 and iCalendar 2.0 -->
<macro name="VCALENDAR_INCOMING_SCRIPT"><![CDATA[
STRING MATCHES[];
}
}
]]></macro>
-
-
<!-- The following email handling scripts are defined as script MACROS because they
are used in multiple <datatype> definitions below. This avoids duplicating these
script's source code in the config file -->
<datatypes>
-
<!-- list of internal fields representing vCard data -->
<fieldlist name="contacts">
<field name="SYNCLVL" type="integer" compare="never"/>
<field name="PHOTO_TYPE" type="integer" compare="never" merge="fillempty"/>
</fieldlist>
-
<!-- vCard profile -->
<mimeprofile name="vCard" fieldlist="contacts">
</profile>
</mimeprofile>
+
<!-- vCard 2.1 datatype, using vCard profile defined above -->
<datatype name="vCard21" basetype="vcard">
<version>2.1</version>
<version>3.0</version>
<use mimeprofile="vCard"/>
</datatype>
-
-
<!-- common field list for events and todos (both represented by vCalendar/iCalendar) -->
<fieldlist name="calendar">
<field name="SYNCLVL" type="integer" compare="never"/>
<field name="ORGANIZER_CN" array="no" type="string" compare="never"/>
</fieldlist>
-
-
<!-- vCalendar with VTODO and VEVENT variants -->
<mimeprofile name="vCalendar" fieldlist="calendar">
</profile>
</mimeprofile>
-
<!-- vCalendar 1.0 datatype, using vCalendar profile defined above -->
<datatype name="vCalendar10" basetype="vcalendar">
<version>1.0</version>
</datatype>
-
<!-- list of internal fields representing plain text note data -->
<fieldlist name="Note">
<field name="SYNCLVL" type="integer" compare="never"/>
</linemap>
</textprofile>
- <datatype name="note" basetype="text">
+ <datatype name="note10" basetype="text">
<use profile="Note"/>
<typestring>text/plain</typestring>
<versionstring>1.0</versionstring>
<versionstring>1.1</versionstring>
</datatype>
-
<!-- list of internal fields representing vBookmark data -->
<fieldlist name="bookmarks">
<field name="REV" type="timestamp" compare="never" age="yes"/>
</fieldlist>
<!-- vBookmark profile -->
- <mimeprofile name="vbookmark" fieldlist="bookmarks">
+ <mimeprofile name="vBookmark" fieldlist="bookmarks">
<profile name="VBKM" nummandatory="0">
<property name="VERSION">
</mimeprofile>
<!-- vBookmark datatype, using vBookmark profile defined above -->
- <datatype name="vbookmark" basetype="mimedir">
+ <datatype name="vBookmark10" basetype="mimedir">
<typestring>text/x-vbookmark</typestring>
<versionstring>1.0</versionstring>
- <use profile="vbookmark"/>
+ <use profile="vBookmark"/>
</datatype>
-
-
<!-- list of internal fields representing email data -->
<fieldlist name="email">
<field name="SYNCLVL" type="integer" compare="never"/>
<field name="ATT_CONTENTS" array="yes" type="blob" compare="never"/>
</fieldlist>
-
<!-- this is the text profile used to generate and decode RFC2822/MIME-Multipart
email messages. -->
<textprofile name="rfc2822_email" fieldlist="email">
</linemap>
</textprofile>
-
<datatype name="email" basetype="text">
<use profile="rfc2822_email"/>
<typestring>text/message</typestring> <!-- this is P800-like -->
</datatype>
-
<!-- Note: This is a proprietary extension datatype for Synthesis AG Windows Mobile SyncML clients.
This format is a compressed form of the standard RFC2822 format. For one, the entire data
is compressed using the zip algorithm (<zippedbindata>), and secondly attachments are included
</datatype>
-
-
<datatype name="email_sonyericsson" basetype="text">
<use profile="rfc2822_email"/>
<typestring>message/rfc822</typestring> <!-- this is M600i/P990-like -->
</datatype>
-
<datatype name="email_nokia9500" basetype="text">
<use profile="rfc2822_email"/>
<typestring>message/x-rfc822</typestring> <!-- this is Nokia 9500/9300-like -->
</fieldmap>
<typesupport>
- <use datatype="note" mode="rw" preferred="yes"/>
+ <use datatype="note10" mode="rw" preferred="yes"/>
<use datatype="note11" mode="rw"/>
</typesupport>
<!-- datatypes supported by this datastore -->
<typesupport>
- <use datatype="vbookmark" mode="rw" preferred="yes"/>
+ <use datatype="vBookmark10" mode="rw" preferred="yes"/>
</typesupport>
</datastore>
</remoterule>
-ÊÊ <remoterule name="SyncJe_Outlook">
-ÊÊÊÊ <!-- Rule for NextHaus SyncJe Outlook Edition -->
-ÊÊÊÊ <model>SyncJe Outlook Edition</model>
+ <remoterule name="SyncJe_Outlook">
+ <!-- Rule for NextHaus SyncJe Outlook Edition -->
+ <model>SyncJe Outlook Edition</model>
-ÊÊÊÊ <ignorectcap>yes</ignorectcap> <!-- can do contact photo sync, but is missing in CTCap -->
+ <ignorectcap>yes</ignorectcap> <!-- can do contact photo sync, but is missing in CTCap -->
<descriptivename>NextHaus SyncJe Outlook Client</descriptivename>
-ÊÊ </remoterule>
-
+ </remoterule>
<!-- End of remote rule list. -->
--- /dev/null
+#! /usr/bin/env perl
+
+sub basename {
+ $_ = shift;
+ s;.*/;;;
+ return $_;
+}
+
+# Concatenate all files ending in .xml in the given directory
+# plus those in a specific subdirectory for client or server.
+# Order lexicographic ascending of the base filename.
+
+sub readfragments {
+ my $dir = shift;
+ my $subdir = shift;
+ my @res = ();
+
+ my @files = ();
+ if (opendir(my $dh, $dir)) {
+ foreach (grep (/.*\.xml$/, readdir($dh))) {
+ push @files, "$dir/$_";
+ }
+ closedir($dh);
+
+ if (opendir(my $dh, "$dir/$subdir")) {
+ foreach (grep (/.*\.xml$/, readdir($dh))) {
+ push @files, "$dir/$subdir/$_";
+ }
+ closedir($dh);
+ }
+ }
+
+ @files = sort { basename($a) <=> basename($b) } @files;
+ foreach (@files) {
+ open(IN, "<$_") || die "cannot read $_: $!";
+ push @res, <IN>;
+ close(IN);
+ }
+
+ return join("", @res);
+}
+
+# replace content of <debug>, <scripting>, <datatypes> and all <remoterule>s
+# with the corresponding shared and/or client/server .xml fragments
+sub update {
+ my $file = shift;
+ my $subdir = shift;
+
+ open(IN, "<$file") || die "cannot read $file: $!";
+ $_ = join("", <IN>);
+ close(IN) || die "closing $file: $!";
+
+ s;(<debug>\n).*(\n *</debug>);$1 . readfragments("debug", $subdir) . $2;se;
+ s;(<scripting>\n).*(\n *</scripting>);$1 . readfragments("scripting", $subdir) . $2;se;
+ s;(<datatypes>\n).*(\n *</datatypes>);$1 . readfragments("datatypes", $subdir) . $2;se;
+ s;(\n *)<remoterule>.*</remoterule>;$1 . readfragments("remoterules", $subdir);se;
+
+ open(OUT, ">$file") || die "cannot write $file: $!";
+ print OUT;
+ close(OUT) || die "closing $file: $!";
+}
+
+update("syncclient_sample_config.xml", "client");
+update("syncserv_sample_config.xml", "server");
deleteAll(createSourceA);
std::string parent, child;
- TestingSyncSourcePtr copy;
+ TestingSyncSourcePtr source, copy;
// check that everything is empty, also resets change counter of sync source B
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
deleteItem(createSourceA, child);
+ SOURCE_ASSERT_NO_FAILURE(source.get(), source.reset(createSourceA()));
+ SOURCE_ASSERT_EQUAL(source.get(), 1, countItems(source.get()));
+ SOURCE_ASSERT_EQUAL(source.get(), 0, countNewItems(source.get()));
+ SOURCE_ASSERT_EQUAL(source.get(), 0, countUpdatedItems(source.get()));
+ SOURCE_ASSERT_EQUAL(source.get(), 0, countDeletedItems(source.get()));
+ CPPUNIT_ASSERT_NO_THROW(source.reset());
+
SOURCE_ASSERT_NO_FAILURE(copy.get(), copy.reset(createSourceB()));
SOURCE_ASSERT_EQUAL(copy.get(), 1, countItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 0, countNewItems(copy.get()));
- SOURCE_ASSERT_EQUAL(copy.get(), 0, countUpdatedItems(copy.get()));
+ // parent might have been updated
+ int updated = countUpdatedItems(copy.get());
+ SOURCE_ASSERT(copy.get(), 0 <= updated && updated <= 1);
SOURCE_ASSERT_EQUAL(copy.get(), 1, countDeletedItems(copy.get()));
SOURCE_ASSERT_EQUAL(copy.get(), 1, countEqual(listDeletedItems(copy.get()), child));
CPPUNIT_ASSERT_NO_THROW(copy.reset());
int ClientTest::dump(ClientTest &client, TestingSyncSource &source, const char *file)
{
BackupReport report;
- VolatileConfigNode node;
+ boost::shared_ptr<ConfigNode> node(new VolatileConfigNode);
rm_r(file);
mkdir_p(file);
CPPUNIT_ASSERT(source.getOperations().m_backupData);
- source.getOperations().m_backupData(file, node, report);
+ source.getOperations().m_backupData(SyncSource::Operations::ConstBackupInfo(),
+ SyncSource::Operations::BackupInfo(SyncSource::Operations::BackupInfo::BACKUP_OTHER, file, node),
+ report);
return 0;
}
FILE_CFLAGS = @FILE_CFLAGS@
FILE_LIBS = @FILE_LIBS@
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB216_CFLAGS = @GLIB216_CFLAGS@
+GLIB216_LIBS = @GLIB216_LIBS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
GLIB_LIBS = @GLIB_LIBS@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
+GNOMEBLUETOOTH_CFLAGS = @GNOMEBLUETOOTH_CFLAGS@
+GNOMEBLUETOOTH_DIR = @GNOMEBLUETOOTH_DIR@
+GNOMEBLUETOOTH_LIBS = @GNOMEBLUETOOTH_LIBS@
GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
GOBJECT_LIBS = @GOBJECT_LIBS@
GREP = @GREP@
KEYRING_LIBS = @KEYRING_LIBS@
LDFLAGS = @LDFLAGS@
LIBEXECDIR = @LIBEXECDIR@
+LIBICAL_AVAILABLE_CFLAGS = @LIBICAL_AVAILABLE_CFLAGS@
+LIBICAL_AVAILABLE_LIBS = @LIBICAL_AVAILABLE_LIBS@
LIBOBJS = @LIBOBJS@
LIBOPENOBEX_CFLAGS = @LIBOPENOBEX_CFLAGS@
LIBOPENOBEX_LIBS = @LIBOPENOBEX_LIBS@
MSGFMT_OPTS = @MSGFMT_OPTS@
MSGMERGE = @MSGMERGE@
NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_LIBS = @NSS_LIBS@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
return join("", @res);
}
-# parameters: file handle with input, width to use for reformatted lines
+# parameters: text, width to use for reformatted lines
# returns list of lines without line breaks
sub Normalize {
- my $in = shift;
+ $_ = shift;
my $width = shift;
- $_ = join( "", <$in> );
s/\r//g;
my @items = ();
my ($file1, $file2) = ($ARGV[0], $ARGV[1]);
- if (-d $file1) {
- open(IN1, "-|:utf8", "find $file1 -type f -print0 | xargs -0 cat") || die "$file1: $!";
- } else {
- open(IN1, "<:utf8", $file1) || die "$file1: $!";
- }
- if (-d $file2) {
- open(IN2, "-|:utf8", "find $file2 -type f -print0 | xargs -0 cat") || die "$file2: $!";
- } else {
- open(IN2, "<:utf8", $file2) || die "$file2: $!";
- }
my $singlewidth = int(($columns - 3) / 2);
$columns = $singlewidth * 2 + 3;
- my @normal1 = Normalize(*IN1{IO}, $singlewidth);
- my @normal2 = Normalize(*IN2{IO}, $singlewidth);
- close(IN1);
- close(IN2);
+ my @normal1;
+ my @normal2;
+
+ if (-d $file1 && -d $file2) {
+ # Both "files" are really directories of individual files.
+ # Don't include files in the comparison which are known
+ # to be identical because the refer to the same inode.
+ # - build map from inode to filename
+ my %files1;
+ my %files2;
+ my @content1;
+ my @content2;
+ my $inode;
+ my $fullname;
+ my $entry;
+ opendir(my $dh, $file1) || die "cannot read $file1: $!";
+ foreach $entry (grep { -f "$file1/$_" } readdir($dh)) {
+ $fullname = "$file1/$entry";
+ $inode = (stat($fullname))[1];
+ $files1{$inode} = $entry;
+ }
+ closedir($dh);
+ # - remove common files, read others
+ opendir(my $dh, $file2) || die "cannot read $file2: $!";
+ foreach $entry (grep { -f "$file2/$_" } readdir($dh)) {
+ $fullname = "$file2/$entry";
+ $inode = (stat($fullname))[1];
+ if ($files1{$inode}) {
+ delete $files1{$inode};
+ } else {
+ open(IN, "<:utf8", "$fullname") || die "$fullname: $!";
+ push @content2, <IN>;
+ }
+ }
+ # - read remaining entries from first dir
+ foreach $entry (values %files1) {
+ $fullname = "$file1/$entry";
+ open(IN, "<:utf8", "$fullname") || die "$fullname: $!";
+ push @content1, <IN>;
+ }
+ @normal1 = Normalize(join("", @content1), $singlewidth);
+ @normal2 = Normalize(join("", @content2), $singlewidth);
+ } else {
+ if (-d $file1) {
+ open(IN1, "-|:utf8", "find $file1 -type f -print0 | xargs -0 cat") || die "$file1: $!";
+ } else {
+ open(IN1, "<:utf8", $file1) || die "$file1: $!";
+ }
+ if (-d $file2) {
+ open(IN2, "-|:utf8", "find $file2 -type f -print0 | xargs -0 cat") || die "$file2: $!";
+ } else {
+ open(IN2, "<:utf8", $file2) || die "$file2: $!";
+ }
+ @normal1 = Normalize(join("", <IN1>), $singlewidth);
+ @normal2 = Normalize(join("", <IN2>), $singlewidth);
+ close(IN1);
+ close(IN2);
+ }
# Produce output where each line is marked as old (aka remove) with o,
# as new (aka added) with n, and as unchanged with u at the beginning.
$in = *STDIN{IO};
}
- print STDOUT join("\n", Normalize($in, $columns)), "\n";
+ print STDOUT join("\n", Normalize(join("", <$in>), $columns)), "\n";
}