removed all references to Funambol header files and definitions

This commit is contained in:
Patrick Ohly 2009-02-17 12:18:15 +01:00 committed by Patrick Ohly
parent d801974f74
commit 43f2c5fec5
32 changed files with 502 additions and 2118 deletions

11
HACKING
View file

@ -58,18 +58,15 @@ Funambol client library or non-default sources - see the "funambol"
configure options for details.
For doing development work the recommended configure line is:
configure SYNCEVOLUTION_CXXFLAGS="-Wall -Werror -Wno-unknown-pragmas" \
configure CXXFLAGS="-Wall -Werror -Wno-unknown-pragmas" \
--enable-unit-tests \
--enable-libcurl
Enabling libcurl explicitly ensures that it gets built even when not
the default.
In contrast to CXXFLAGS, SYNCEVOLUTION_CXXFLAGS adds these flags only
to the compilation of source files from the SyncEvolution source code
repository, but not the client library. -Wno-unknown-pragmas is
required to avoid warnings triggered by '#pragma }', a trick to
preserve indention after 'extern "C" {' in
-Wno-unknown-pragmas is required to avoid warnings triggered by
'#pragma }', a trick to preserve indention after 'extern "C" {' in
/usr/include/evolution-data-server-1.12/libical/
Working with the Code
@ -220,7 +217,7 @@ Compiling for Mac OS X
Configuring for development:
<path>/configure --with-funambol-src=<path> \
--enable-addressbook \
SYNCEVOLUTION_CXXFLAGS="-Wall -Werror -Wno-unknown-pragmas" \
CXXFLAGS="-Wall -Werror -Wno-unknown-pragmas" \
LDFLAGS="-framework Addressbook -framework CoreServices" \
CXXFLAGS=-g \
CFLAGS=-g

View file

@ -32,36 +32,36 @@ else
FUNAMBOLSRC_DEF="FUNAMBOLSRC_REPO"
fi
AC_ARG_WITH(funambol-src,
AS_HELP_STRING([--with-funambol-src=<base directory|svn URL|git URL>],
[Specifies location of the Funambol 'client-api/native' source code.
Use this instead of --with-funambol when the client library is to
be compiled as part of the SyncEvolution compilation. In release
versions of SyncEvolution, a copy of the client library is bundled
under 'src/client-api' and compiled unless something else is
specified. --with-funambol-src can be given a path to sources
checked out already, a Subversion repository URL or a git repository
URL. When given a repository URL, then the configure script
will checkout the sources into 'src/client-api-copy' or
update that working copy if the directory already exists.
Default: bundled source in src/client-api (in released SyncEvolution sources),
FUNAMBOLSRC_REPO otherwise.]),
[FUNAMBOLSRC="$withval"], [FUNAMBOLSRC="$FUNAMBOLSRC_DEF"; REVISION="FUNAMBOLSRC_REVISION"])
dnl AC_ARG_WITH(funambol-src,
dnl AS_HELP_STRING([--with-funambol-src=<base directory|svn URL|git URL>],
dnl [Specifies location of the Funambol 'client-api/native' source code.
dnl Use this instead of --with-funambol when the client library is to
dnl be compiled as part of the SyncEvolution compilation. In release
dnl versions of SyncEvolution, a copy of the client library is bundled
dnl under 'src/client-api' and compiled unless something else is
dnl specified. --with-funambol-src can be given a path to sources
dnl checked out already, a Subversion repository URL or a git repository
dnl URL. When given a repository URL, then the configure script
dnl will checkout the sources into 'src/client-api-copy' or
dnl update that working copy if the directory already exists.
dnl Default: bundled source in src/client-api (in released SyncEvolution sources),
dnl FUNAMBOLSRC_REPO otherwise.]),
dnl [FUNAMBOLSRC="$withval"], [FUNAMBOLSRC="$FUNAMBOLSRC_DEF"; REVISION="FUNAMBOLSRC_REVISION"])
AC_ARG_WITH(sync4j-src,
AS_HELP_STRING([--with-sync4j-src=<base directory>],
[alias for --with-funambol-src]),
[FUNAMBOLSRC="$withval"])
dnl AC_ARG_WITH(sync4j-src,
dnl AS_HELP_STRING([--with-sync4j-src=<base directory>],
dnl [alias for --with-funambol-src]),
dnl [FUNAMBOLSRC="$withval"])
AC_ARG_WITH(funambol-username,
AS_HELP_STRING([--with-funambol-username=<svn username>],
[username to use when checking out --with-funambol-src sources from Subversion, default 'guest']),
[USERNAME="$withval"], [USERNAME="guest"])
dnl AC_ARG_WITH(funambol-username,
dnl AS_HELP_STRING([--with-funambol-username=<svn username>],
dnl [username to use when checking out --with-funambol-src sources from Subversion, default 'guest']),
dnl [USERNAME="$withval"], [USERNAME="guest"])
AC_ARG_WITH(funambol-revision,
AS_HELP_STRING([--with-funambol-revision=<git tag/branch/hash or Subversion revision>],
[Identifies which source revision to use from --with-funambol-src repository, empty string stands for latest. Default for default --funambol-src: FUNAMBOLSRC_REVISION]),
[REVISION="$withval"])
dnl AC_ARG_WITH(funambol-revision,
dnl AS_HELP_STRING([--with-funambol-revision=<git tag/branch/hash or Subversion revision>],
dnl [Identifies which source revision to use from --with-funambol-src repository, empty string stands for latest. Default for default --funambol-src: FUNAMBOLSRC_REVISION]),
dnl [REVISION="$withval"])
AC_ARG_ENABLE(shared,
AS_HELP_STRING([--enable-shared],
@ -136,7 +136,7 @@ AC_SUBST(CORE_LDADD_DEP)
# preserve src/client-api by default,
# always
CLEAN_CLIENT_SRC=
FUNAMBOL_LIB=$PWD/src/build-client-api/src/libfunambol.la
dnl FUNAMBOL_LIB=$PWD/src/build-client-api/src/libfunambol.la
AC_SUBST(CLEAN_CLIENT_SRC)
@ -216,115 +216,117 @@ AC_SUBST(TRANSPORT_LIBS)
AC_SUBST(TRANSPORT_CFLAGS)
# absolute patch to source of Funambol client library
CLIENT_API_SRC=no-client-api-source
AC_SUBST(CLIENT_API_SRC)
if test ! "$FUNAMBOL"; then
if test "$FUNAMBOLSRC"; then
# default: checkout a copy of the sources, remove it during maintainer-clean and distclean
CLEAN_CLIENT_SRC=client-api-copy
CLIENT_API_SRC=$PWD/src/client-api-copy
dnl # absolute patch to source of Funambol client library
dnl CLIENT_API_SRC=no-client-api-source
dnl AC_SUBST(CLIENT_API_SRC)
dnl if test ! "$FUNAMBOL"; then
dnl if test "$FUNAMBOLSRC"; then
dnl # default: checkout a copy of the sources, remove it during maintainer-clean and distclean
dnl CLEAN_CLIENT_SRC=client-api-copy
dnl CLIENT_API_SRC=$PWD/src/client-api-copy
AC_MSG_NOTICE( [updating the content of $CLIENT_API_SRC from $FUNAMBOLSRC] )
case "$FUNAMBOLSRC" in
*://*) protocol="`echo $FUNAMBOLSRC | sed -e 's;://.*;;'`";;
*) protocol="file";;
esac
dnl AC_MSG_NOTICE( [updating the content of $CLIENT_API_SRC from $FUNAMBOLSRC] )
dnl case "$FUNAMBOLSRC" in
dnl *://*) protocol="`echo $FUNAMBOLSRC | sed -e 's;://.*;;'`";;
dnl *) protocol="file";;
dnl esac
mkdir -p src
case $protocol in
file)
# use existing copy of the sources
CLEAN_CLIENT_SRC=
case "$FUNAMBOLSRC" in
/*) CLIENT_API_SRC="$FUNAMBOLSRC";;
*) CLIENT_API_SRC="$PWD/$FUNAMBOLSRC";;
esac
;;
*svn*|*http*)
FUNAMBOLSRCREV="$FUNAMBOLSRC"
if test "$REVISION"; then
revarg="-r $REVISION "
if `echo $FUNAMBOLSRC | grep '@[0123456789]*'` >/dev/null; then
:
else
FUNAMBOLSRCREV="$FUNAMBOLSRC@$REVISION"
fi
fi
if test -d $CLIENT_API_SRC ; then
( set -x; cd $CLIENT_API_SRC && svn --username=$USERNAME switch $revarg "$FUNAMBOLSRC" ) || AC_ERROR([updating from $FUNAMBOLSRC failed])
else
(set -x; svn --username=$USERNAME checkout $revarg "$FUNAMBOLSRCREV" $CLIENT_API_SRC ) || AC_ERROR([checking out $FUNAMBOLSRC failed])
fi
;;
*git*)
if test -d $CLIENT_API_SRC ; then
( set -x; cd $CLIENT_API_SRC && git fetch "$FUNAMBOLSRC" ) || AC_ERROR([updating from $FUNAMBOLSRC failed])
else
( set -x; git clone "$FUNAMBOLSRC" $CLIENT_API_SRC ) || AC_ERROR([cloning $FUNAMBOLSRC failed])
fi
if test "$REVISION"; then
# git 1.6 finds tags and branches without explicit prefix, 1.4.4.4 doesn't
( set -x; cd $CLIENT_API_SRC &&
(git checkout "$REVISION" ||
git checkout "tags/$REVISION" ||
git checkout "origin/$REVISION") ) || AC_ERROR([checking out $FUNAMBOLSRC failed])
fi
;;
esac
else
# use existing copy of the sources; beware of
# out-of-tree compilation
case $srcdir in
/*) CLIENT_API_SRC="$srcdir/src/client-api";;
*) CLIENT_API_SRC="$PWD/$srcdir/src/client-api";;
esac
fi
dnl mkdir -p src
dnl case $protocol in
dnl file)
dnl # use existing copy of the sources
dnl CLEAN_CLIENT_SRC=
dnl case "$FUNAMBOLSRC" in
dnl /*) CLIENT_API_SRC="$FUNAMBOLSRC";;
dnl *) CLIENT_API_SRC="$PWD/$FUNAMBOLSRC";;
dnl esac
dnl ;;
dnl *svn*|*http*)
dnl FUNAMBOLSRCREV="$FUNAMBOLSRC"
dnl if test "$REVISION"; then
dnl revarg="-r $REVISION "
dnl if `echo $FUNAMBOLSRC | grep '@[0123456789]*'` >/dev/null; then
dnl :
dnl else
dnl FUNAMBOLSRCREV="$FUNAMBOLSRC@$REVISION"
dnl fi
dnl fi
dnl if test -d $CLIENT_API_SRC ; then
dnl ( set -x; cd $CLIENT_API_SRC && svn --username=$USERNAME switch $revarg "$FUNAMBOLSRC" ) || AC_ERROR([updating from $FUNAMBOLSRC failed])
dnl else
dnl (set -x; svn --username=$USERNAME checkout $revarg "$FUNAMBOLSRCREV" $CLIENT_API_SRC ) || AC_ERROR([checking out $FUNAMBOLSRC failed])
dnl fi
dnl ;;
dnl *git*)
dnl if test -d $CLIENT_API_SRC ; then
dnl ( set -x; cd $CLIENT_API_SRC && git fetch "$FUNAMBOLSRC" ) || AC_ERROR([updating from $FUNAMBOLSRC failed])
dnl else
dnl ( set -x; git clone "$FUNAMBOLSRC" $CLIENT_API_SRC ) || AC_ERROR([cloning $FUNAMBOLSRC failed])
dnl fi
dnl if test "$REVISION"; then
dnl # git 1.6 finds tags and branches without explicit prefix, 1.4.4.4 doesn't
dnl ( set -x; cd $CLIENT_API_SRC &&
dnl (git checkout "$REVISION" ||
dnl git checkout "tags/$REVISION" ||
dnl git checkout "origin/$REVISION") ) || AC_ERROR([checking out $FUNAMBOLSRC failed])
dnl fi
dnl ;;
dnl esac
dnl else
dnl # use existing copy of the sources; beware of
dnl # out-of-tree compilation
dnl case $srcdir in
dnl /*) CLIENT_API_SRC="$srcdir/src/client-api";;
dnl *) CLIENT_API_SRC="$PWD/$srcdir/src/client-api";;
dnl esac
dnl fi
( cd $CLIENT_API_SRC/build/autotools && ( test -f configure || sh autogen.sh ) )
dnl ( cd $CLIENT_API_SRC/build/autotools && ( test -f configure || sh autogen.sh ) )
if test -f $CLIENT_API_SRC/build/autotools/configure; then
CLIENT_CONFIGURE="$CLIENT_API_SRC/build/autotools/configure"
chmod u+x $CLIENT_API_SRC/build/autotools/configure $CLIENT_API_SRC/build/autotools/config.sub $CLIENT_API_SRC/build/autotools/config.guess
dnl if test -f $CLIENT_API_SRC/build/autotools/configure; then
dnl CLIENT_CONFIGURE="$CLIENT_API_SRC/build/autotools/configure"
dnl chmod u+x $CLIENT_API_SRC/build/autotools/configure $CLIENT_API_SRC/build/autotools/config.sub $CLIENT_API_SRC/build/autotools/config.guess
# use local copy of the sources, with dependencies
# to trigger building the client library
FUNAMBOL_SUBDIR=$PWD/src/build-client-api
FUNAMBOL_DEP=$PWD/src/build-client-api/src/libfunambol.la
dnl # use local copy of the sources, with dependencies
dnl # to trigger building the client library
dnl FUNAMBOL_SUBDIR=$PWD/src/build-client-api
dnl FUNAMBOL_DEP=$PWD/src/build-client-api/src/libfunambol.la
FUNAMBOL_CFLAGS="-I$FUNAMBOL_SUBDIR/include/posix -I$FUNAMBOL_SUBDIR/include/common -I$FUNAMBOL_SUBDIR/include -I$FUNAMBOL_SUBDIR/test"
FUNAMBOL_LIBS="-L$FUNAMBOL_SUBDIR/src -lfunambol"
dnl FUNAMBOL_CFLAGS="-I$FUNAMBOL_SUBDIR/include/posix -I$FUNAMBOL_SUBDIR/include/common -I$FUNAMBOL_SUBDIR/include -I$FUNAMBOL_SUBDIR/test"
dnl FUNAMBOL_LIBS="-L$FUNAMBOL_SUBDIR/src -lfunambol"
AC_MSG_NOTICE( [configuring the client library] )
# Passing some specific configure arguments to the client library's
# configure makes sense (e.g., --enable-unit-tests) or is
# required (--disable-dependency-tracking when compiling for
# multiple architectures on Mac OS X).
cxx_lib_args=`for i in --disable-dependency-tracking --enable-unit-tests; do
if echo $ac_configure_args | grep -e $i >/dev/null; then
echo $i;
fi;
done`
if test "$enable_shared" == "yes"; then
# Okay, this is a shortcut: strictly speaking we would have
# to check with autoconf for the right flags...
FUNAMBOL_LIB_SHARED_FLAGS="-DPIC -fPIC"
fi
if (set -x; mkdir -p $FUNAMBOL_SUBDIR && cd $FUNAMBOL_SUBDIR && $CLIENT_CONFIGURE $CLIENT_CONFIGURE_OPTIONS --build=$build_alias --host=$host_alias --target=$target_alias --disable-shared --with-transport-agent=curl CFLAGS="$CFLAGS $FUNAMBOL_LIB_SHARED_FLAGS" CXXFLAGS="$CXXFLAGS $FUNAMBOL_LIB_SHARED_FLAGS" $cxx_lib_args); then true; else
AC_MSG_ERROR( [configuring client library failed] )
fi
else
AC_MSG_ERROR( [either --with-funambol or --with-funambol-src have to be used] )
fi
else
if test -f $FUNAMBOL/include/funambol/common/spds/SyncItem.h; then
FUNAMBOL_CFLAGS="-I$FUNAMBOL/include/funambol/posix -I$FUNAMBOL/include/funambol/common -I$FUNAMBOL/include/funambol"
FUNAMBOL_LIBS="-L$FUNAMBOL/lib -lfunambol"
else
AC_MSG_ERROR( [$FUNAMBOL does seem to be valid (e.g. include/funambol/spds/common/SyncItem.h is missing)] )
fi
fi
dnl AC_MSG_NOTICE( [configuring the client library] )
dnl # Passing some specific configure arguments to the client library's
dnl # configure makes sense (e.g., --enable-unit-tests) or is
dnl # required (--disable-dependency-tracking when compiling for
dnl # multiple architectures on Mac OS X).
dnl cxx_lib_args=`for i in --disable-dependency-tracking --enable-unit-tests; do
dnl if echo $ac_configure_args | grep -e $i >/dev/null; then
dnl echo $i;
dnl fi;
dnl done`
dnl if test "$enable_shared" == "yes"; then
dnl # Okay, this is a shortcut: strictly speaking we would have
dnl # to check with autoconf for the right flags...
dnl FUNAMBOL_LIB_SHARED_FLAGS="-DPIC -fPIC"
dnl fi
dnl if (set -x; mkdir -p $FUNAMBOL_SUBDIR && cd $FUNAMBOL_SUBDIR && $CLIENT_CONFIGURE $CLIENT_CONFIGURE_OPTIONS --build=$build_alias --host=$host_alias --target=$target_alias --disable-shared --with-transport-agent=curl CFLAGS="$CFLAGS $FUNAMBOL_LIB_SHARED_FLAGS" CXXFLAGS="$CXXFLAGS $FUNAMBOL_LIB_SHARED_FLAGS" $cxx_lib_args); then true; else
dnl AC_MSG_ERROR( [configuring client library failed] )
dnl fi
dnl else
dnl AC_MSG_ERROR( [either --with-funambol or --with-funambol-src have to be used] )
dnl fi
dnl else
dnl if test -f $FUNAMBOL/include/funambol/common/spds/SyncItem.h; then
dnl FUNAMBOL_CFLAGS="-I$FUNAMBOL/include/funambol/posix -I$FUNAMBOL/include/funambol/common -I$FUNAMBOL/include/funambol"
dnl FUNAMBOL_LIBS="-L$FUNAMBOL/lib -lfunambol"
dnl else
dnl AC_MSG_ERROR( [$FUNAMBOL does seem to be valid (e.g. include/funambol/spds/common/SyncItem.h is missing)] )
dnl fi
dnl fi
dnl TODO: compile Synthesis library the same way Funambol was compiled/bundled before?
dnl Makefiles are unchanged for that purpose.
FUNAMBOL_CFLAGS="$FUNAMBOL_CFLAGS $SYNTHESIS_CFLAGS"
AC_SUBST(FUNAMBOL_CFLAGS)

View file

@ -118,12 +118,13 @@ distclean-local:
# executed. The workaround is to explicitly set them as undefined on the
# link line.
client_test_SOURCES = client-test-app.cpp $(CORE_SOURCES)
CLIENT_LIB_TEST_FILES = ClientTest.h ClientTest.cpp client-test-main.cpp \
testcases/vcard21.vcf \
testcases/vcard30.vcf \
testcases/ical20.ics \
testcases/imemo20.ics \
testcases/itodo20.ics
CLIENT_LIB_TEST_FILES =
# ClientTest.h ClientTest.cpp client-test-main.cpp \
# testcases/vcard21.vcf \
# testcases/vcard30.vcf \
# testcases/ical20.ics \
# testcases/imemo20.ics \
# testcases/itodo20.ics
nodist_client_test_SOURCES = $(CLIENT_LIB_TEST_FILES)
client_test_CPPFLAGS = -DHAVE_CONFIG_H -DENABLE_INTEGRATION_TESTS -DENABLE_UNIT_TESTS $(AM_CPPFLAGS)
client_test_CXXFLAGS = `cppunit-config --cflags` $(SYNCEVOLUTION_CXXFLAGS)

View file

@ -229,24 +229,12 @@ SyncItem *EvolutionCalendarSource::createItem(const string &luid)
ItemID id(luid);
string icalstr = retrieveItemAsString(id);
auto_ptr<SyncItem> item(new SyncItem(luid.c_str()));
cxxptr<SyncItem> item(new SyncItem(), "SyncItem");
item->setKey(luid);
item->setData(icalstr.c_str(), icalstr.size());
item->setDataType("text/calendar");
item->setModificationTime(0);
return item.release();
}
void EvolutionCalendarSource::setItemStatusThrow(const char *key, int status)
{
switch (status) {
case STC_CONFLICT_RESOLVED_WITH_SERVER_DATA:
SE_LOG_ERROR(this, NULL, "item %.80s: conflict, will be replaced by server\n", key);
break;
}
TrackingSyncSource::setItemStatusThrow(key, status);
}
EvolutionCalendarSource::InsertItemResult EvolutionCalendarSource::insertItem(const string &luid, const SyncItem &item)
{
bool update = !luid.empty();
@ -584,9 +572,8 @@ static string extractProp(const char *data, const char *keyword)
void EvolutionCalendarSource::logItem(const SyncItem &item, const string &info, bool debug)
{
if (getLevel() >= (debug ? Logger::DEBUG : Logger::INFO)) {
const char *keyptr = item.getKey();
string key;
if (!keyptr || !keyptr[0]) {
string key = item.getKey();
if (key.empty()) {
// get UID from data via simple string search; doesn't have to be perfect
const char *data = (const char *)item.getData();
string uid = extractProp(data, "\nUID:");
@ -596,8 +583,6 @@ void EvolutionCalendarSource::logItem(const SyncItem &item, const string &info,
} else {
key = ItemID::getLUID(uid, rid);
}
} else {
key = keyptr;
}
SE_LOG(debug ? Logger::DEBUG : Logger::INFO, this, NULL, "%s: %s", key.c_str(), info.c_str());
}

View file

@ -53,7 +53,6 @@ class EvolutionCalendarSource : public TrackingSyncSource
//
virtual void listAllItems(RevisionMap_t &revisions);
virtual InsertItemResult insertItem(const string &luid, const SyncItem &item);
virtual void setItemStatusThrow(const char *key, int status);
virtual void deleteItem(const string &luid);
virtual void logItem(const string &luid, const string &info, bool debug = false);
virtual void logItem(const SyncItem &item, const string &info, bool debug = false);

View file

@ -18,8 +18,6 @@ using namespace std;
#include "SyncEvolutionUtil.h"
#include "Logging.h"
#include "vocl/VConverter.h"
using namespace vocl;
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
@ -331,27 +329,29 @@ void EvolutionContactSource::exportData(ostream &out)
}
}
SyncItem *EvolutionContactSource::createItem(const string &uid)
SyncItem *EvolutionContactSource::createItem(const string &luid)
{
logItem( uid, "extracting from EV", true );
logItem(luid, "extracting from EV", true);
EContact *contact;
GError *gerror = NULL;
if (! e_book_get_contact( m_addressbook,
uid.c_str(),
&contact,
&gerror ) ) {
throwError( string( "reading contact " ) + uid,
gerror );
if (!e_book_get_contact(m_addressbook,
luid.c_str(),
&contact,
&gerror)) {
throwError(string("reading contact ") + luid,
gerror);
}
eptr<EContact, GObject> contactptr( contact, "contact" );
eptr<char> vcardstr(e_vcard_to_string( &contactptr->parent,
EVC_FORMAT_VCARD_30 ) );
eptr<EContact, GObject> contactptr(contact, "contact");
eptr<char> vcardstr(e_vcard_to_string(&contactptr->parent,
EVC_FORMAT_VCARD_30));
if (!vcardstr) {
throwError(string("failure extracting contact from Evolution " ) + uid);
throwError(string("failure extracting contact from Evolution " ) + luid);
}
SE_LOG_DEBUG(this, NULL, "%s", vcardstr.get());
#if 0
// @TODO reimplement Evolution hacks via Synthesis datatype conversions
std::auto_ptr<VObject> vobj(VConverter::parse(vcardstr));
if (vobj.get() == 0) {
throwError(string("failure parsing contact " ) + uid);
@ -477,17 +477,20 @@ SyncItem *EvolutionContactSource::createItem(const string &uid)
arrayptr<char> finalstr(vobj->toString(), "VOCL string");
SE_LOG_DEBUG(this, NULL, "after conversion:");
SE_LOG_DEBUG(this, NULL, "%s", (char *)finalstr);
#endif
auto_ptr<SyncItem> item( new SyncItem( uid.c_str() ) );
item->setData( (char *)finalstr, strlen(finalstr) );
item->setDataType( getMimeType() );
item->setModificationTime( 0 );
cxxptr<SyncItem> item(new SyncItem(), "SyncItem");
item->setKey(luid);
item->setData(vcardstr.get(), strlen(vcardstr.get()));
return item.release();
}
string EvolutionContactSource::preparseVCard(SyncItem& item)
{
return item.getData();
#if 0
// @TODO Synthesis data conversion
string data = (const char *)item.getData();
// convert to 3.0 to get rid of quoted-printable encoded
// non-ASCII chars, because Evolution does not support
@ -672,52 +675,13 @@ string EvolutionContactSource::preparseVCard(SyncItem& item)
SE_LOG_DEBUG(this, NULL, "after conversion to 3.0:");
SE_LOG_DEBUG(this, NULL, "%s", data.c_str());
return data;
#endif
}
void EvolutionContactSource::setItemStatusThrow(const char *key, int status)
SyncMLStatus EvolutionContactSource::addItemThrow(SyncItem& item)
{
switch (status) {
case STC_CONFLICT_RESOLVED_WITH_SERVER_DATA: {
// make a copy before allowing the server to overwrite it
SE_LOG_ERROR(this, NULL, "contact %s: conflict, will be replaced by server contact - create copy", key);
EContact *contact;
GError *gerror = NULL;
if (! e_book_get_contact( m_addressbook,
key,
&contact,
&gerror ) ) {
SE_LOG_ERROR(this, NULL, "item %.80s: reading original for copy failed", key);
break;
}
eptr<EContact, GObject> contactptr( contact, "contact" );
EContact *copy = e_contact_duplicate(contact);
eptr<EContact, GObject> contactcopyptr(copy);
if(!copy ||
! e_book_add_contact(m_addressbook,
copy,
&gerror)) {
SE_LOG_ERROR(this, NULL, "item %.80s: making copy failed", key);
break;
}
break;
}
default:
EvolutionSyncSource::setItemStatusThrow(key, status);
break;
}
}
int EvolutionContactSource::addItemThrow(SyncItem& item)
{
int status = STC_OK;
string data;
if( strcmp(item.getDataType(), "raw" ) ) {
data = preparseVCard(item);
} else {
data = (const char *)item.getData();
}
SyncMLStatus status = STATUS_OK;
string data = item.getData();
eptr<EContact, GObject> contact(e_contact_new_from_vcard(data.c_str()));
if( contact ) {
GError *gerror = NULL;
@ -733,9 +697,9 @@ int EvolutionContactSource::addItemThrow(SyncItem& item)
return status;
}
int EvolutionContactSource::updateItemThrow(SyncItem& item)
SyncMLStatus EvolutionContactSource::updateItemThrow(SyncItem& item)
{
int status = STC_OK;
SyncMLStatus status = STATUS_OK;
string data = preparseVCard(item);
eptr<EContact, GObject> contact(e_contact_new_from_vcard(data.c_str()));
if( contact ) {
@ -750,7 +714,7 @@ int EvolutionContactSource::updateItemThrow(SyncItem& item)
// and committing once more, but that did not solve the problem.
//
// TODO: test with current Evolution
e_contact_set( contact, E_CONTACT_UID, (void *)item.getKey() );
e_contact_set(contact, E_CONTACT_UID, (void *)item.getKey().c_str());
if ( e_book_commit_contact(m_addressbook, contact, &gerror) ) {
const char *uid = (const char *)e_contact_get_const(contact, E_CONTACT_UID);
if (uid) {
@ -783,15 +747,15 @@ int EvolutionContactSource::updateItemThrow(SyncItem& item)
return status;
}
int EvolutionContactSource::deleteItemThrow(SyncItem& item)
SyncMLStatus EvolutionContactSource::deleteItemThrow(SyncItem& item)
{
int status = STC_OK;
SyncMLStatus status = STATUS_OK;
GError *gerror = NULL;
if (!e_book_remove_contact( m_addressbook, item.getKey(), &gerror ) ) {
if (!e_book_remove_contact(m_addressbook, item.getKey().c_str(), &gerror)) {
if (gerror->domain == E_BOOK_ERROR &&
gerror->code == E_BOOK_ERROR_CONTACT_NOT_FOUND) {
SE_LOG_DEBUG(this, NULL, "%s: %s: request to delete non-existant contact ignored",
getName(), item.getKey());
getName(), item.getKey().c_str());
g_clear_error(&gerror);
} else {
throwError( string( "deleting contact " ) + item.getKey(),
@ -886,9 +850,7 @@ void EvolutionContactSource::logItem(const SyncItem &item, const string &info, b
line += "<unnamed contact>";
}
if (!item.getKey() ) {
line += ", NULL UID (?!)";
} else if (!strlen( item.getKey() )) {
if (item.getKey().empty()) {
line += ", empty UID";
} else {
line += ", ";
@ -896,10 +858,10 @@ void EvolutionContactSource::logItem(const SyncItem &item, const string &info, b
EContact *contact;
GError *gerror = NULL;
if (e_book_get_contact( m_addressbook,
item.getKey(),
&contact,
&gerror )) {
if (e_book_get_contact(m_addressbook,
item.getKey().c_str(),
&contact,
&gerror)) {
eptr<EContact, GObject> contactptr( contact, "contact" );
line += ", EV ";

View file

@ -49,10 +49,9 @@ class EvolutionContactSource : public EvolutionSyncSource
bool needPartial,
bool deleteLocal);
virtual void endSyncThrow();
virtual void setItemStatusThrow(const char *key, int status);
virtual int addItemThrow(SyncItem& item);
virtual int updateItemThrow(SyncItem& item);
virtual int deleteItemThrow(SyncItem& item);
virtual SyncMLStatus addItemThrow(SyncItem& item);
virtual SyncMLStatus updateItemThrow(SyncItem& item);
virtual SyncMLStatus deleteItemThrow(SyncItem& item);
virtual void logItem(const string &uid, const string &info, bool debug = false);
virtual void logItem(const SyncItem &item, const string &info, bool debug = false);

View file

@ -20,9 +20,8 @@ SyncItem *EvolutionMemoSource::createItem(const string &luid)
ItemID id(luid);
eptr<icalcomponent> comp(retrieveItem(id));
auto_ptr<SyncItem> item(new SyncItem(luid.c_str()));
item->setData("", 0);
cxxptr<SyncItem> item(new SyncItem(), "SyncItem");
item->setKey(luid);
icalcomponent *cal = icalcomponent_get_first_component(comp, ICAL_VCALENDAR_COMPONENT);
if (!cal) {
cal = comp;
@ -90,23 +89,20 @@ SyncItem *EvolutionMemoSource::createItem(const string &luid)
item->setData(dostext, strlen(dostext));
}
}
item->setDataType("text/plain");
item->setModificationTime(0);
return item.release();
}
EvolutionCalendarSource::InsertItemResult EvolutionMemoSource::insertItem(const string &luid, const SyncItem &item)
{
const char *type = item.getDataType();
string type = item.getDataType();
// fall back to inserting iCalendar 2.0 if
// real SyncML server has sent vCalendar 1.0 or iCalendar 2.0
// or the test system inserts such an item
if (!type[0] ||
!strcasecmp(type, "raw") ||
!strcasecmp(type, "text/x-vcalendar") ||
!strcasecmp(type, "text/calendar")) {
if (!strcasecmp(type.c_str(), "raw") ||
!strcasecmp(type.c_str(), "text/x-vcalendar") ||
!strcasecmp(type.c_str(), "text/calendar")) {
return EvolutionCalendarSource::insertItem(luid, item);
}

View file

@ -151,12 +151,9 @@ SyncItem *FileSyncSource::createItem(const string &uid)
}
string content = out.str();
auto_ptr<SyncItem> item(new SyncItem(uid.c_str()));
cxxptr<SyncItem> item(new SyncItem(), "SyncItem");
item->setKey(uid);
item->setData(content.c_str(), content.size());
item->setDataType(getMimeType());
// probably not even used by Funambol client library...
item->setModificationTime(0);
return item.release();
}

View file

@ -29,7 +29,7 @@ syncsqlite_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS)
# SQLiteContactSource does not support all fields from Funambol vCard 2.1
# test cases: filter them out before testing
../../testcases/sqlite_vcard21.vcf: $(FUNAMBOL_SUBDIR)/test/test/testcases/vcard21.vcf
mkdir -p ${@D}
perl -e '$$_ = join("", <>); s/^(ADR|TEL|EMAIL|PHOTO).*?(?=^\S)//msg; s/;X-EVOLUTION-UI-SLOT=\d+//g; print;' $< >$@
all: ../../testcases/sqlite_vcard21.vcf
#../../testcases/sqlite_vcard21.vcf: $(FUNAMBOL_SUBDIR)/test/test/testcases/vcard21.vcf
# mkdir -p ${@D}
# perl -e '$$_ = join("", <>); s/^(ADR|TEL|EMAIL|PHOTO).*?(?=^\S)//msg; s/;X-EVOLUTION-UI-SLOT=\d+//g; print;' $< >$@
# all: ../../testcases/sqlite_vcard21.vcf

View file

@ -49,8 +49,13 @@ EvolutionSyncClient::EvolutionSyncClient(const string &server,
m_quiet(false),
m_engine(new sysync::TEngineModuleBridge())
{
// Use libsynthesis that we were linked against. The name
// of a .so could be given here, too, to use that instead.
// Use libsynthesis that we were linked against. The name of a
// .so could be given here, too, to use that instead. This
// instance of the engine is used outside of the sync session
// itself. doSync() then creates another engine for the sync
// itself. That is necessary because the engine shutdown depends
// on the context of the sync (in particular instantiated sync
// sources).
sysync::TSyError err = m_engine->Connect("[]", 0,
sysync::DBG_PLUGIN_NONE|
sysync::DBG_PLUGIN_INT|
@ -312,9 +317,7 @@ class SourceList : public vector<EvolutionSyncSource *> {
LogDir m_logdir; /**< our logging directory */
bool m_prepared; /**< remember whether syncPrepare() dumped databases successfully */
bool m_doLogging; /**< true iff additional files are to be written during sync */
SyncClient &m_client; /**< client which holds the sync report after a sync */
bool m_reportTodo; /**< true if syncDone() shall print a final report */
boost::scoped_array<SyncSource *> m_sourceArray; /** owns the array that is expected by SyncClient::sync() */
const bool m_quiet; /**< avoid redundant printing to screen */
string m_previousLogdir; /**< remember previous log dir before creating the new one */
@ -361,11 +364,10 @@ public:
}
}
SourceList(const string &server, bool doLogging, SyncClient &client, bool quiet) :
SourceList(const string &server, bool doLogging, bool quiet) :
m_logdir(server),
m_prepared(false),
m_doLogging(doLogging),
m_client(client),
m_reportTodo(true),
m_quiet(quiet)
{
@ -502,8 +504,8 @@ public:
for (EvolutionSyncSource::ItemLocation location = EvolutionSyncSource::ITEM_LOCAL;
location <= EvolutionSyncSource::ITEM_REMOTE;
location = EvolutionSyncSource::ItemLocation(int(location) + 1)) {
for (EvolutionSyncSource::ItemState state = EvolutionSyncSource::ITEM_STATE_ADDED;
state <= EvolutionSyncSource::ITEM_STATE_REMOVED;
for (EvolutionSyncSource::ItemState state = EvolutionSyncSource::ITEM_ADDED;
state <= EvolutionSyncSource::ITEM_REMOVED;
state = EvolutionSyncSource::ItemState(int(state) + 1)) {
cout << right << setw(number_width) <<
source->getItemStat(location, state, EvolutionSyncSource::ITEM_REJECT);
@ -515,24 +517,24 @@ public:
}
int total_conflicts =
source->getItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_CONFLICT_SERVER_WON) +
source->getItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_CONFLICT_CLIENT_WON) +
source->getItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_CONFLICT_DUPLICATED);
cout << right << setw(number_width + 1) << total_conflicts;
cout << " |\n";
stringstream sent, received;
sent << source->getItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_SENT_BYTES) / 1024 <<
" KB sent by client";
received << source->getItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_RECEIVED_BYTES) / 1024 <<
" KB received";
cout << "|" << left << setw(name_width) << "" << " |" <<
@ -547,7 +549,7 @@ public:
result = EvolutionSyncSource::ItemResult(int(result) + 1)) {
int count;
if ((count = source->getItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
result)) != 0 || true) {
stringstream line;
line << count << " " <<
@ -562,7 +564,7 @@ public:
}
int total_matched = source->getItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_MATCH);
if (total_matched) {
cout << "|" << left << setw(name_width) << "" << "| " << left <<
@ -599,19 +601,6 @@ public:
}
}
/** returns current sources as array as expected by SyncClient::sync(), memory owned by this class */
SyncSource **getSourceArray() {
m_sourceArray.reset(new SyncSource *[size() + 1]);
int index = 0;
BOOST_FOREACH(EvolutionSyncSource *source, *this) {
m_sourceArray[index] = source;
index++;
}
m_sourceArray[index] = 0;
return &m_sourceArray[0];
}
/** returns names of active sources */
set<string> getSources() {
set<string> res;
@ -783,15 +772,15 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
extra2=# updated,
extra3=# deleted) */
source.setItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_ADDED,
EvolutionSyncSource::ITEM_ADDED,
EvolutionSyncSource::ITEM_TOTAL,
extra1);
source.setItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_UPDATED,
EvolutionSyncSource::ITEM_UPDATED,
EvolutionSyncSource::ITEM_TOTAL,
extra2);
source.setItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_REMOVED,
EvolutionSyncSource::ITEM_REMOVED,
EvolutionSyncSource::ITEM_TOTAL,
extra3);
break;
@ -800,15 +789,15 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
extra2=# updated,
extra3=# deleted) */
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ADDED,
EvolutionSyncSource::ITEM_ADDED,
EvolutionSyncSource::ITEM_TOTAL,
extra1);
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_UPDATED,
EvolutionSyncSource::ITEM_UPDATED,
EvolutionSyncSource::ITEM_TOTAL,
extra2);
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_REMOVED,
EvolutionSyncSource::ITEM_REMOVED,
EvolutionSyncSource::ITEM_TOTAL,
extra3);
break;
@ -816,18 +805,18 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
/* datastore statistics for local/remote rejects (extra1=# locally rejected,
extra2=# remotely rejected) */
source.setItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_REJECT,
extra1);
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_REJECT,
extra2);
break;
case PEV_DSSTATS_S:
/* datastore statistics for server slowsync (extra1=# slowsync matches) */
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_MATCH,
extra1);
break;
@ -836,15 +825,15 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
extra2=# client won,
extra3=# duplicated) */
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_CONFLICT_SERVER_WON,
extra1);
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_CONFLICT_CLIENT_WON,
extra2);
source.setItemStat(EvolutionSyncSource::ITEM_REMOTE,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_CONFLICT_DUPLICATED,
extra3);
break;
@ -852,11 +841,11 @@ void EvolutionSyncClient::displaySourceProgress(sysync::TEngineProgressEventType
/* datastore statistics for data volume (extra1=outgoing bytes,
extra2=incoming bytes) */
source.setItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_SENT_BYTES,
extra1);
source.setItemStat(EvolutionSyncSource::ITEM_LOCAL,
EvolutionSyncSource::ITEM_STATE_ANY,
EvolutionSyncSource::ITEM_ANY,
EvolutionSyncSource::ITEM_RECEIVED_BYTES,
extra2);
break;
@ -949,21 +938,6 @@ EvolutionSyncSource *EvolutionSyncClient::findSource(const char *name)
return m_sourceListPtr ? (*m_sourceListPtr)[name] : NULL;
}
AbstractSyncSourceConfig* EvolutionSyncClient::getAbstractSyncSourceConfig(const char* name) const
{
return m_sourceListPtr ? (*m_sourceListPtr)[name] : NULL;
}
AbstractSyncSourceConfig* EvolutionSyncClient::getAbstractSyncSourceConfig(unsigned int i) const
{
return m_sourceListPtr ? (*m_sourceListPtr)[i] : NULL;
}
unsigned int EvolutionSyncClient::getAbstractSyncSourceConfigsCount() const
{
return m_sourceListPtr ? m_sourceListPtr->size() : 0;
}
void EvolutionSyncClient::setConfigFilter(bool sync, const FilterConfigNode::ConfigFilter &filter)
{
map<string, string>::const_iterator hasSync = filter.find(EvolutionSyncSourceConfig::m_sourcePropSync.getName());
@ -1146,7 +1120,7 @@ int EvolutionSyncClient::sync()
}
// redirect logging as soon as possible
SourceList sourceList(m_server, m_doLogging, *this, m_quiet);
SourceList sourceList(m_server, m_doLogging, m_quiet);
m_sourceListPtr = &sourceList;
try {
@ -1189,29 +1163,13 @@ int EvolutionSyncClient::sync()
}
// give derived class also a chance to update the configs
prepare(sourceList.getSourceArray());
prepare(sourceList);
// ready to go: dump initial databases and prepare for final report
sourceList.syncPrepare();
#ifndef SYNTHESIS
// do it
res = SyncClient::sync(*this, sourceList.getSourceArray());
// store modified properties: must be done even after failed
// sync because the source's anchor might have been reset
flush();
if (res) {
if (getLastErrorCode() && getLastErrorMsg() && getLastErrorMsg()[0]) {
throwError(getLastErrorMsg());
}
// no error code/description?!
throwError("sync failed without an error description, check log");
}
#else
// run sync session
doSync();
#endif
// all went well: print final report before cleaning up
sourceList.syncDone(true);
@ -1233,13 +1191,11 @@ int EvolutionSyncClient::sync()
return res;
}
void EvolutionSyncClient::prepare(SyncSource **sources) {
void EvolutionSyncClient::prepare(const std::vector<EvolutionSyncSource *> &sources) {
if (m_syncMode != SYNC_NONE) {
for (SyncSource **source = sources;
*source;
source++) {
(*source)->setPreferredSyncMode(m_syncMode);
}
// BOOST_FOREACH(EvolutionSyncSource *source, sources) {
// @TODO source->setPreferredSyncMode(m_syncMode);
// }
}
}
@ -1251,6 +1207,35 @@ void EvolutionSyncClient::doSync()
sysync::KeyH subkeyH;
string s;
// create new sync engine for the duration of this function
class SwapEngine {
EvolutionSyncClient &m_client;
sysync::TEngineModuleBridge *m_oldengine;
public:
SwapEngine(EvolutionSyncClient &client) :
m_client(client) {
sysync::TEngineModuleBridge *syncengine = new sysync::TEngineModuleBridge();
sysync::TSyError err;
if (!syncengine ||
(err = syncengine->Connect("[]", 0,
sysync::DBG_PLUGIN_NONE|
sysync::DBG_PLUGIN_INT|
sysync::DBG_PLUGIN_DB|
sysync::DBG_PLUGIN_EXOT|
sysync::DBG_PLUGIN_ALL))) {
m_client.throwError("create Syntesis engine for sync session");
}
m_oldengine = m_client.swapEngine(syncengine);
}
~SwapEngine() {
sysync::TEngineModuleBridge *syncengine =
m_client.swapEngine(m_oldengine);
delete syncengine;
}
} swapengine(*this);
err = getEngine().OpenKeyByPath(keyH, NULL, "/configvars", 0);
if (err) {
throwError("open config vars");
@ -1551,7 +1536,7 @@ void EvolutionSyncClient::status()
throwError("cannot proceed without configuration");
}
SourceList sourceList(m_server, false, *this, false);
SourceList sourceList(m_server, false, false);
initSources(sourceList);
BOOST_FOREACH(EvolutionSyncSource *source, sourceList) {
source->checkPassword(*this);
@ -1560,7 +1545,7 @@ void EvolutionSyncClient::status()
source->open();
}
sourceList.setLogdir(getLogDir(), 0, LOG_LEVEL_NONE);
sourceList.setLogdir(getLogDir(), 0, 0);
LoggerBase::instance().setLevel(Logger::INFO);
string prevLogdir = sourceList.getPrevLogdir();
bool found = access(prevLogdir.c_str(), R_OK|X_OK) == 0;

View file

@ -9,8 +9,7 @@
#include "EvolutionSmartPtr.h"
#include "SyncEvolutionConfig.h"
#include <client/SyncClient.h>
#include <spds/SyncManagerConfig.h>
#include "SyncML.h"
#include <string>
#include <set>
@ -42,7 +41,7 @@ namespace sysync {
* implementation of those uses stdin/out.
*
*/
class EvolutionSyncClient : public SyncClient, public EvolutionSyncConfig, public ConfigUserInterface {
class EvolutionSyncClient : public EvolutionSyncConfig, public ConfigUserInterface {
const string m_server;
const set<string> m_sources;
const bool m_doLogging;
@ -146,11 +145,6 @@ class EvolutionSyncClient : public SyncClient, public EvolutionSyncConfig, publi
*/
static EvolutionSyncSource *findSource(const char *name);
/* AbstractSyncConfig API */
virtual AbstractSyncSourceConfig* getAbstractSyncSourceConfig(const char* name) const;
virtual AbstractSyncSourceConfig* getAbstractSyncSourceConfig(unsigned int i) const;
virtual unsigned int getAbstractSyncSourceConfigsCount() const;
/**
* intercept config filters
*
@ -166,6 +160,12 @@ class EvolutionSyncClient : public SyncClient, public EvolutionSyncConfig, publi
sysync::TEngineModuleBridge &getEngine() { return *m_engine; }
const sysync::TEngineModuleBridge &getEngine() const { return *m_engine; }
sysync::TEngineModuleBridge *swapEngine(sysync::TEngineModuleBridge *newengine) {
sysync::TEngineModuleBridge *oldengine = m_engine;
m_engine = newengine;
return oldengine;
}
/**
* Return skeleton Synthesis client XML configuration.
*
@ -216,7 +216,7 @@ class EvolutionSyncClient : public SyncClient, public EvolutionSyncConfig, publi
*
* @param sources a NULL terminated array of all active sources
*/
virtual void prepare(SyncSource **sources);
virtual void prepare(const std::vector<EvolutionSyncSource *> &sources);
/**
* instantiate transport agent

View file

@ -77,9 +77,7 @@ void EvolutionSyncSource::handleException()
try {
throw;
} catch (std::exception &ex) {
setErrorF(getLastErrorCode() == ERR_NONE ? ERR_UNSPECIFIED : getLastErrorCode(),
"%s", ex.what());
SE_LOG_ERROR(this, NULL, "%s", getLastErrorMsg());
SE_LOG_ERROR(this, NULL, "%s", ex.what());
setFailed(true);
}
}
@ -342,20 +340,19 @@ void EvolutionSyncSource::getDatastoreXML(string &xml)
xml = xmlstream.str();
}
int EvolutionSyncSource::beginSync() throw()
SyncMLStatus EvolutionSyncSource::beginSync(SyncMode mode) throw()
{
SyncMode mode = getSyncMode();
// start background thread if not running yet:
// necessary to catch problems with Evolution backend
EvolutionSyncClient::startLoopThread();
try {
// @TODO: force slow sync if something goes wrong
//
// reset anchors now, once we proceed there is no going back
// (because the change marker is about to be moved)
// and the sync must either complete or result in a slow sync
// the next time
getConfig().setLast(0);
const char *error = getenv("SYNCEVOLUTION_BEGIN_SYNC_ERROR");
if (error && strstr(error, getName())) {
@ -409,9 +406,9 @@ int EvolutionSyncSource::beginSync() throw()
rewindItems();
} catch( ... ) {
handleException();
return 1;
return STATUS_FATAL;
}
return 0;
return STATUS_OK;
}
void EvolutionSyncSource::rewindItems() throw()
@ -419,19 +416,19 @@ void EvolutionSyncSource::rewindItems() throw()
m_allItems.rewind();
}
EvolutionSyncSource::NextItemState EvolutionSyncSource::nextItem(string *data, string &luid) throw()
SyncItem::State EvolutionSyncSource::nextItem(string *data, string &luid) throw()
{
/** @TODO: avoid reading data if not necessary */
SyncItem *item = m_allItems.iterate();
NextItemState state = ITEM_EOF;
SyncItem::State state = SyncItem::NO_MORE_ITEMS;
if (item) {
if (m_newItems.find(item->getKey()) != m_newItems.end()) {
state = ITEM_NEW;
state = SyncItem::NEW;
} else if (m_updatedItems.find(item->getKey()) != m_updatedItems.end()) {
state = ITEM_UPDATED;
state = SyncItem::UPDATED;
} else {
state = ITEM_UNCHANGED;
state = SyncItem::UNCHANGED;
}
if (data) {
data->assign((const char *)item->getData(), item->getDataSize());
@ -441,7 +438,7 @@ EvolutionSyncSource::NextItemState EvolutionSyncSource::nextItem(string *data, s
return state;
}
int EvolutionSyncSource::endSync() throw()
SyncMLStatus EvolutionSyncSource::endSync() throw()
{
try {
endSyncThrow();
@ -449,41 +446,31 @@ int EvolutionSyncSource::endSync() throw()
handleException();
}
// Do _not_ tell the caller (SyncManager) if an error occurred
// @TODO: Do _not_ tell the caller (SyncManager) if an error occurred
// because that causes Sync4jClient to abort processing for all
// sync sources. Instead deal with failed sync sources in
// EvolutionSyncClient::sync().
return 0;
return STATUS_OK;
}
void EvolutionSyncSource::setItemStatus(const char *key, int status) throw()
{
try {
// TODO: logging
setItemStatusThrow(key, status);
} catch (...) {
handleException();
}
}
int EvolutionSyncSource::addItem(SyncItem& item) throw()
SyncMLStatus EvolutionSyncSource::addItem(SyncItem& item) throw()
{
return processItem("add", &EvolutionSyncSource::addItemThrow, item, true);
}
int EvolutionSyncSource::updateItem(SyncItem& item) throw()
SyncMLStatus EvolutionSyncSource::updateItem(SyncItem& item) throw()
{
return processItem("update", &EvolutionSyncSource::updateItemThrow, item, true);
}
int EvolutionSyncSource::deleteItem(SyncItem& item) throw()
SyncMLStatus EvolutionSyncSource::deleteItem(SyncItem& item) throw()
{
return processItem("delete", &EvolutionSyncSource::deleteItemThrow, item, false);
}
int EvolutionSyncSource::removeAllItems() throw()
SyncMLStatus EvolutionSyncSource::removeAllItems() throw()
{
int status = 0;
SyncMLStatus status = STATUS_OK;
try {
BOOST_FOREACH(const string &key, m_allItems) {
@ -495,17 +482,17 @@ int EvolutionSyncSource::removeAllItems() throw()
}
} catch (...) {
handleException();
status = 1;
status = STATUS_FATAL;
}
return status;
}
int EvolutionSyncSource::processItem(const char *action,
int (EvolutionSyncSource::*func)(SyncItem& item),
SyncItem& item,
bool needData) throw()
SyncMLStatus EvolutionSyncSource::processItem(const char *action,
SyncMLStatus (EvolutionSyncSource::*func)(SyncItem& item),
SyncItem& item,
bool needData) throw()
{
int status = STC_COMMAND_FAILED;
SyncMLStatus status = STATUS_FATAL;
try {
logItem(item, action);
@ -514,7 +501,7 @@ int EvolutionSyncSource::processItem(const char *action,
// Shouldn't happen, but it did with one server and thus this
// security check was added to prevent segfaults.
logItem(item, "ignored due to missing data");
status = STC_OK;
status = STATUS_OK;
} else {
status = (this->*func)(item);
}
@ -526,21 +513,6 @@ int EvolutionSyncSource::processItem(const char *action,
return status;
}
void EvolutionSyncSource::setItemStatusThrow(const char *key, int status)
{
switch (status) {
case STC_ALREADY_EXISTS:
// found pair during slow sync, that's okay
break;
default:
if (status < 200 || status > 300) {
SE_LOG_ERROR(this, NULL, "unexpected SyncML status response %d for item %.80s\n",
status, key);
setFailed(true);
}
}
}
void EvolutionSyncSource::sleepSinceModification(int seconds)
{
time_t current = time(NULL);
@ -670,16 +642,13 @@ SyncItem *EvolutionSyncSource::Items::iterate()
if (&m_source.m_deletedItems == this) {
// just tell caller the uid of the deleted item
// and the type that it probably had
SyncItem *item = new SyncItem( uid.c_str() );
item->setDataType(m_source.getMimeType());
return item;
cxxptr<SyncItem> item(new SyncItem());
item->setKey(uid);
return item.release();
} else {
// retrieve item with all its data
try {
cxxptr<SyncItem> item(m_source.createItem(uid));
if (item) {
item->setState(m_state);
}
return item.release();
} catch(...) {
m_source.handleException();

View file

@ -9,6 +9,8 @@
#include "SyncEvolutionConfig.h"
#include "EvolutionSmartPtr.h"
#include "Logging.h"
#include "eds_abi_wrapper.h"
#include "SyncML.h"
using namespace SyncEvolution;
#include <boost/shared_ptr.hpp>
@ -21,11 +23,6 @@ using namespace std;
#include <time.h>
#include <spds/SyncSource.h>
#include <spdm/ManagementNode.h>
#include "Logging.h"
#include "eds_abi_wrapper.h"
class EvolutionSyncSource;
#include <synthesis/sync_declarations.h>
@ -242,7 +239,7 @@ class RegisterSyncSourceTest
* sources which normally use one format internally, but also
* support another one (EvolutionContactSource).
*/
static int dump(ClientTest &client, SyncSource &source, const char *file);
static int dump(ClientTest &client, EvolutionSyncSource &source, const char *file);
const string m_configName;
const string m_testCaseName;
@ -263,7 +260,6 @@ class TestRegistry : public vector<const RegisterSyncSourceTest *>
}
};
/**
* SyncEvolution accesses all sources through this interface. This
* class also implements common functionality for all SyncSources:
@ -284,25 +280,23 @@ class TestRegistry : public vector<const RegisterSyncSourceTest *>
*
* It also adds Evolution specific interfaces and utility functions.
*/
class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig, public LoggerBase
class EvolutionSyncSource : public EvolutionSyncSourceConfig, public LoggerBase
{
public:
/**
* Creates a new Evolution sync source.
*/
EvolutionSyncSource(const EvolutionSyncSourceParams &params) :
SyncSource(params.m_name.c_str(), NULL),
EvolutionSyncSourceConfig(params.m_name, params.m_nodes),
m_changeId( params.m_changeId ),
m_allItems( *this, "existing", SYNC_STATE_NONE ),
m_newItems( *this, "new", SYNC_STATE_NEW ),
m_updatedItems( *this, "updated", SYNC_STATE_UPDATED ),
m_deletedItems( *this, "deleted", SYNC_STATE_DELETED ),
m_allItems( *this, "existing", SyncItem::NONE ),
m_newItems( *this, "new", SyncItem::NEW ),
m_updatedItems( *this, "updated", SyncItem::UPDATED ),
m_deletedItems( *this, "deleted", SyncItem::DELETED ),
m_isModified( false ),
m_modTimeStamp(0),
m_hasFailed( false )
{
setConfig(this);
memset(m_stat, 0, sizeof(m_stat));
}
virtual ~EvolutionSyncSource() {}
@ -412,8 +406,25 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
* (between SyncEvolution_Module_CreateContext() and
* SyncEvolution_Module_DeleteContext())
*/
sysync::SDK_InterfaceType *getSynthesisAPI() { return m_synthesisAPI; }
void setSynthesisAPI(sysync::SDK_InterfaceType *synthesisAPI) { m_synthesisAPI = synthesisAPI; }
sysync::SDK_InterfaceType *getSynthesisAPI() {
return m_synthesisAPI.empty() ?
NULL :
m_synthesisAPI[m_synthesisAPI.size() - 1];
}
/**
* change the Synthesis API that is used by the source
*/
void pushSynthesisAPI(sysync::SDK_InterfaceType *synthesisAPI) {
m_synthesisAPI.push_back(synthesisAPI);
}
/**
* remove latest Synthesis API and return to previous one (if any)
*/
void popSynthesisAPI() {
m_synthesisAPI.pop_back();
}
/**
* Convenience function, to be called inside a catch() block of
@ -519,13 +530,6 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
virtual SyncItem* getNextItemKey() throw() { return m_allItems.iterate(); }
/**@}*/
enum NextItemState {
ITEM_UNCHANGED, /**< item is unchanged since last sync */
ITEM_NEW, /**< new item */
ITEM_UPDATED, /**< item was updated since last sync */
ITEM_EOF, /**< no more items */
ITEM_ERROR /**< item couldn't be extracted */
};
/**
* get information about next item
*
@ -533,7 +537,7 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
* @retval luid local ID of item
* @return status of item or error
*/
virtual NextItemState nextItem(string *data, string &luid) throw();
virtual SyncItem::State nextItem(string *data, string &luid) throw();
/**
* restart reading all items, automatically called at end of beginSync()
@ -545,12 +549,11 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
* and implemented via the corresponding *Throw() calls
*/
/**@{*/
virtual int beginSync() throw();
virtual int endSync() throw();
virtual void setItemStatus(const char *key, int status) throw();
virtual int addItem(SyncItem& item) throw();
virtual int updateItem(SyncItem& item) throw();
virtual int deleteItem(SyncItem& item) throw();
virtual SyncMLStatus beginSync(SyncMode mode) throw();
virtual SyncMLStatus endSync() throw();
virtual SyncMLStatus addItem(SyncItem& item) throw();
virtual SyncMLStatus updateItem(SyncItem& item) throw();
virtual SyncMLStatus deleteItem(SyncItem& item) throw();
/**@}*/
/**
@ -564,13 +567,7 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
*
* @return 0 for success, non-zero for failure
*/
virtual int removeAllItems() throw();
/**
* Disambiguate getName(): we have inherited it from both SyncSource and
* AbstractSyncSourceConfig. Both must return the same string.
*/
const char *getName() throw() { return SyncSource::getName(); }
virtual SyncMLStatus removeAllItems() throw();
/**
* source specific part of beginSync() - throws exceptions in case of error
@ -589,10 +586,9 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
*/
/**@{*/
virtual void endSyncThrow() = 0;
virtual void setItemStatusThrow(const char *key, int status);
virtual int addItemThrow(SyncItem& item) = 0;
virtual int updateItemThrow(SyncItem& item) = 0;
virtual int deleteItemThrow(SyncItem& item) = 0;
virtual SyncMLStatus addItemThrow(SyncItem& item) = 0;
virtual SyncMLStatus updateItemThrow(SyncItem& item) = 0;
virtual SyncMLStatus deleteItemThrow(SyncItem& item) = 0;
/**@}*/
/**
@ -690,12 +686,10 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
ITEM_LOCATION_MAX
};
enum ItemState {
// TODO: remove _STATE_ once we got rid of Funambol header files;
// currently those have conflicting defines
ITEM_STATE_ADDED,
ITEM_STATE_UPDATED,
ITEM_STATE_REMOVED,
ITEM_STATE_ANY,
ITEM_ADDED,
ITEM_UPDATED,
ITEM_REMOVED,
ITEM_ANY,
ITEM_STATE_MAX
};
enum ItemResult {
@ -736,10 +730,10 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
const_iterator m_it;
EvolutionSyncSource &m_source;
const string m_type;
const SyncState m_state;
const SyncItem::State m_state;
public:
Items( EvolutionSyncSource &source, const string &type, SyncState state ) :
Items( EvolutionSyncSource &source, const string &type, SyncItem::State state ) :
m_source( source ),
m_type( type ),
m_state( state )
@ -790,10 +784,10 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
/**
* private wrapper function for add/delete/updateItemThrow()
*/
int processItem(const char *action,
int (EvolutionSyncSource::*func)(SyncItem& item),
SyncItem& item,
bool needData) throw();
SyncMLStatus processItem(const char *action,
SyncMLStatus (EvolutionSyncSource::*func)(SyncItem& item),
SyncItem& item,
bool needData) throw();
/** time stamp of latest database modification, for sleepSinceModification() */
time_t m_modTimeStamp;
@ -808,7 +802,7 @@ class EvolutionSyncSource : public SyncSource, public EvolutionSyncSourceConfig,
* SyncEvolution_Module_DeleteContext(), in other words, while
* the engine is running.
*/
sysync::SDK_InterfaceType *m_synthesisAPI;
std::vector<sysync::SDK_InterfaceType *> m_synthesisAPI;
/** storage for getItemStat() */
int m_stat[ITEM_LOCATION_MAX][ITEM_STATE_MAX][ITEM_RESULT_MAX];

View file

@ -13,16 +13,6 @@ else
noinst_LTLIBRARIES = libsyncevolution.la
endif
VOCL_SOURCES = \
vocl/VObject.h \
vocl/VProperty.h \
vocl/VConverter.h \
vocl/posixadapter.h \
\
vocl/VObject.cpp \
vocl/VProperty.cpp \
vocl/VConverter.cpp
CORE_SOURCES = \
ConfigTree.h \
ConfigNode.h \
@ -78,9 +68,8 @@ CORE_SOURCES = \
FileConfigTree.cpp \
\
TrackingSyncSource.h \
TrackingSyncSource.cpp \
\
$(VOCL_SOURCES)
TrackingSyncSource.cpp
libsyncevolution_la_SOURCES = $(CORE_SOURCES)
libsyncevolution_la_LIBADD = @EPACKAGE_LIBS@ @GLIB_LIBS@ @FUNAMBOL_LIBS@ $(TRANSPORT_LIBS) @LIBS@ $(SYNTHESIS_LIBS)

View file

@ -6,8 +6,6 @@
#include "FilterConfigNode.h"
#include "spds/AbstractSyncConfig.h"
#include "spds/AbstractSyncSourceConfig.h"
#include <boost/shared_ptr.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
@ -446,7 +444,7 @@ class ConfigStringCache {
* uses a FileConfigTree instance. Other implementations would be
* possible.
*/
class EvolutionSyncConfig : public AbstractSyncConfig {
class EvolutionSyncConfig {
public:
/**
* Opens the configuration for a specific server,
@ -627,10 +625,6 @@ class EvolutionSyncConfig : public AbstractSyncConfig {
*/
/**@{*/
virtual AbstractSyncSourceConfig* getAbstractSyncSourceConfig(const char* name) const { return NULL; }
virtual AbstractSyncSourceConfig* getAbstractSyncSourceConfig(unsigned int i) const { return NULL; }
virtual unsigned int getAbstractSyncSourceConfigsCount() const { return 0; }
virtual const char* getUsername() const;
virtual void setUsername(const string &value, bool temporarily = false);
virtual const char* getPassword() const;
@ -790,7 +784,7 @@ struct ConstSyncSourceNodes {
* Some properties are not configurable and have to be provided
* by derived classes.
*/
class EvolutionSyncSourceConfig : public AbstractSyncSourceConfig {
class EvolutionSyncSourceConfig {
public:
EvolutionSyncSourceConfig(const string &name, const SyncSourceNodes &nodes);
@ -944,9 +938,9 @@ class EvolutionSyncSourceConfig : public AbstractSyncSourceConfig {
* returning an empty array implies that it supports all aspects.
* This is the default implementation of this call.
*
* @return an ArrayList of CTCap
* @TODO: per-source capabilities
*/
virtual const ArrayList& getCtCaps() const { static const ArrayList dummy; return dummy; }
// virtual const ArrayList& getCtCaps() const { static const ArrayList dummy; return dummy; }
/**@}*/

View file

@ -2,10 +2,8 @@
* Copyright (C) 2008 Patrick Ohly
*/
#include <config.h>
#include "SyncEvolutionUtil.h"
#include "EvolutionSyncClient.h"
#include <base/test.h>
#include <boost/scoped_array.hpp>
#include <boost/foreach.hpp>

View file

@ -5,8 +5,6 @@
#ifndef INCL_SYNCEVOLUTION_UTIL
# define INCL_SYNCEVOLUTION_UTIL
#include <base/test.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>

116
src/core/SyncML.h Normal file
View file

@ -0,0 +1,116 @@
/*
* Copyright (C) 2009 Patrick Ohly
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
#ifndef INCL_SYNCML
#define INCL_SYNCML
#include <string>
enum SyncMode {
SYNC_NONE,
SYNC_TWO_WAY,
SYNC_SLOW,
SYNC_ONE_WAY_FROM_CLIENT,
SYNC_REFRESH_FROM_CLIENT,
SYNC_ONE_WAY_FROM_SERVER,
SYNC_REFRESH_FROM_SERVER,
SYNC_MODE_MAX
};
/**
* simple container for SyncML items
*/
class SyncItem {
private:
/**
* Data, might not be text. nul-byte not included in data size.
*/
std::string m_data;
/**
* Local unique ID of the item.
*/
std::string m_luid;
/**
* Empty string indicates the default format specified for a sync
* source. Might be set to a mime type (e.g. "text/calendar") to
* override the default format.
*/
std::string m_datatype;
public:
std::string getKey() const { return m_luid; }
void setKey(const std::string &key) { m_luid = key; }
const char *getData() const { return m_data.c_str(); }
size_t getDataSize() const { return m_data.size(); }
void setData(const char *data, size_t size) { m_data.assign(data, size); }
void setDataType(const std::string &datatype) { m_datatype = datatype; }
std::string getDataType() const { return m_datatype; }
/** result of change tracking and iteration over items */
enum State {
/** undefined state */
NONE,
/** not changed */
UNCHANGED,
/** item added */
NEW,
/** item updated */
UPDATED,
/** item deleted (only key, but no data available) */
DELETED,
/** end of iteration */
NO_MORE_ITEMS,
/** error reading item */
ERROR,
/** end of enumeration */
STATE_MAX,
};
};
/**
* result of SyncML operations, same codes as in HTTP and the Synthesis engine
*/
enum SyncMLStatus {
/** ok */
STATUS_OK = 0,
/** no content / end of file / end of iteration / empty/NULL value */
STATUS_NO_CONTENT = 204,
/** external data has been merged */
STATUS_DATA_MERGED = 207,
/** forbidden / access denied */
STATUS_FORBIDDEN = 403,
/** object not found / unassigned field */
STATUS_NOT_FOUND = 404,
/** command not allowed */
STATUS_COMMAND_NOT_ALLOWED = 405,
/** command failed / fatal DB error */
STATUS_FATAL = 500,
/** general DB error */
STATUS_DATASTORE_FAILURE = 510,
/** database / memory full error */
STATUS_FULL = 420,
STATUS_MAX = 0x7FFFFFF
};
#endif // INCL_SYNCML

View file

@ -58,7 +58,7 @@ TSyError SyncEvolution_Module_CreateContext( CContext *mContext, cAppCharP mod
TSyError err = LOCERR_WRONGUSAGE;
EvolutionSyncSource *source = EvolutionSyncClient::findSource(mContextName);
if (source) {
source->setSynthesisAPI(mCB);
source->pushSynthesisAPI(mCB);
*mContext = (CContext)source;
err = LOCERR_OK;
}
@ -138,7 +138,7 @@ TSyError SyncEvolution_Module_DeleteContext( CContext mContext )
{
EvolutionSyncSource *source = MoC(mContext);
DEBUG_DB(source->getSynthesisAPI(), MyDB, Mo_DC, "'%s'", source->getName());
source->setSynthesisAPI(NULL);
source->popSynthesisAPI();
return LOCERR_OK;
}
@ -404,7 +404,7 @@ TSyError SyncEvolution_CreateContext( CContext *aContext, cAppCharP aContextName
TSyError err = LOCERR_WRONGUSAGE;
EvolutionSyncSource *source = EvolutionSyncClient::findSource(aContextName);
if (source) {
source->setSynthesisAPI(aCB);
source->pushSynthesisAPI(aCB);
*aContext = (CContext)source;
err = LOCERR_OK;
}
@ -587,12 +587,7 @@ TSyError SyncEvolution_StartDataRead( CContext aContext, cAppCharP lastToken,
TSyError res;
// tell EvolutionSyncSource to be prepared for anything
source->setSyncMode(SYNC_NONE);
if (source->beginSync()) {
res = DB_Fatal;
} else {
res = LOCERR_OK;
}
res = source->beginSync(SYNC_NONE);
return res;
}
@ -607,14 +602,14 @@ TSyError SyncEvolution_ReadNextItemAsKey( CContext aContext, ItemID aID, KeyH aI
TSyError res = LOCERR_OK;
string luid;
switch (source->nextItem(NULL, luid)) {
case EvolutionSyncSource::ITEM_UNCHANGED:
case SyncItem::UNCHANGED:
*aStatus = ReadNextItem_Unchanged;
break;
case EvolutionSyncSource::ITEM_NEW:
case EvolutionSyncSource::ITEM_UPDATED:
case SyncItem::NEW:
case SyncItem::UPDATED:
*aStatus = ReadNextItem_Changed;
break;
case EvolutionSyncSource::ITEM_EOF:
case SyncItem::NO_MORE_ITEMS:
*aStatus = ReadNextItem_EOF;
break;
default:
@ -731,15 +726,9 @@ TSyError SyncEvolution_InsertItemAsKey( CContext aContext, KeyH aItemKey, ItemID
if (!res) {
SyncItem item;
item.setData(data, len);
switch (source->addItem(item)) {
case STC_CONFLICT_RESOLVED_WITH_MERGE:
case STC_OK:
newID->item = StrAlloc(item.getKey());
newID->parent = StrAlloc("");
break;
default:
res = DB_Fatal;
}
res = source->addItem(item);
newID->item = StrAlloc(item.getKey().c_str());
newID->parent = StrAlloc("");
}
delete [] data;
@ -778,16 +767,10 @@ TSyError SyncEvolution_UpdateItemAsKey( CContext aContext, KeyH aItemKey, cItemI
SyncItem item;
item.setData(data, len);
item.setKey(aID->item);
switch (source->updateItem(item)) {
case STC_CONFLICT_RESOLVED_WITH_MERGE:
case STC_OK:
if (strcmp(item.getKey(), aID->item)) {
updID->item = StrAlloc(item.getKey());
updID->parent = StrAlloc("");
}
break;
default:
res = DB_Fatal;
res = source->updateItem(item);
if (item.getKey() == aID->item) {
updID->item = StrAlloc(item.getKey().c_str());
updID->parent = StrAlloc("");
}
}
@ -818,13 +801,7 @@ TSyError SyncEvolution_DeleteItem( CContext aContext, cItemID aID )
TSyError res = LOCERR_OK;
SyncItem item;
item.setKey(aID->item);
switch (source->deleteItem(item)) {
case STC_OK:
break;
default:
res = DB_Fatal;
break;
}
res = source->deleteItem(item);
return res;
}
@ -904,6 +881,6 @@ TSyError SyncEvolution_DeleteContext( CContext aContext )
/**** CAN BE ADAPTED BY USER ****/
EvolutionSyncSource *source = DBC( aContext );
DEBUG_DB( source->getSynthesisAPI(), MyDB,Da_DC, "%s", source->getName() );
source->popSynthesisAPI();
return LOCERR_OK;
}

View file

@ -126,7 +126,7 @@ void TrackingSyncSource::exportData(ostream &out)
}
}
int TrackingSyncSource::addItemThrow(SyncItem& item)
SyncMLStatus TrackingSyncSource::addItemThrow(SyncItem& item)
{
InsertItemResult res = insertItem("", item);
item.setKey(res.m_uid.c_str());
@ -134,10 +134,10 @@ int TrackingSyncSource::addItemThrow(SyncItem& item)
throwError("could not add item");
}
m_trackingNode->setProperty(res.m_uid, res.m_revision);
return res.m_merged ? STC_CONFLICT_RESOLVED_WITH_MERGE : STC_OK;
return res.m_merged ? STATUS_DATA_MERGED : STATUS_OK;
}
int TrackingSyncSource::updateItemThrow(SyncItem& item)
SyncMLStatus TrackingSyncSource::updateItemThrow(SyncItem& item)
{
const string uid = item.getKey();
InsertItemResult res = insertItem(uid, item);
@ -149,17 +149,13 @@ int TrackingSyncSource::updateItemThrow(SyncItem& item)
throwError("could not update item");
}
m_trackingNode->setProperty(res.m_uid, res.m_revision);
return res.m_merged ? STC_CONFLICT_RESOLVED_WITH_MERGE : STC_OK;
return res.m_merged ? STATUS_DATA_MERGED : STATUS_OK;
}
int TrackingSyncSource::deleteItemThrow(SyncItem& item)
SyncMLStatus TrackingSyncSource::deleteItemThrow(SyncItem& item)
{
const string uid = item.getKey();
deleteItem(uid);
m_trackingNode->removeProperty(uid);
return STC_OK;
}
void TrackingSyncSource::setItemStatusThrow(const char *uid, int status)
{
return STATUS_OK;
}

View file

@ -198,17 +198,15 @@ class TrackingSyncSource : public EvolutionSyncSource
virtual void logItem(const string &uid, const string &info, bool debug = false) = 0;
virtual void logItem(const SyncItem &item, const string &info, bool debug = false) = 0;
virtual void setItemStatusThrow(const char *key, int status);
private:
/* implementations of EvolutionSyncSource callbacks */
virtual void beginSyncThrow(bool needAll,
bool needPartial,
bool deleteLocal);
virtual void endSyncThrow();
virtual int addItemThrow(SyncItem& item);
virtual int updateItemThrow(SyncItem& item);
virtual int deleteItemThrow(SyncItem& item);
virtual SyncMLStatus addItemThrow(SyncItem& item);
virtual SyncMLStatus updateItemThrow(SyncItem& item);
virtual SyncMLStatus deleteItemThrow(SyncItem& item);
boost::shared_ptr<ConfigNode> m_trackingNode;
};

View file

@ -1,4 +0,0 @@
The code in this directory is a copy of the Funambol 3.x C++
client api code, revision sdkcpp_3_0_17. It was forked because
the upstream development broke the vCard 2.1 <-> 3.0 conversion
that SyncEvolution needs.

View file

@ -1,314 +0,0 @@
/**
* Copyright (C) 2003-2006 Funambol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include "posixadapter.h"
#include "VConverter.h"
#include "base/util/WString.h"
namespace vocl {
VObject* VConverter::parse(wchar_t* buffer) {
wchar_t *objType = extractObjectType(buffer);
wchar_t *objVersion = extractObjectVersion(buffer);
if(!objType)
return NULL;
VObject* vo = new VObject();
vo->setVersion(objVersion);
VProperty *prop;
wchar_t* buffCopy = new wchar_t[wcslen(buffer) + 1];
wcscpy(buffCopy, buffer);
while ( true ) {
prop = readFieldHeader(buffCopy);
if (!prop) {
break;
}
if ( readFieldBody(*vo, buffCopy, prop )) {
// this makes a copy of prop, we still have to free it
vo->addProperty(prop);
}
delete prop;
}
delete [] buffCopy; buffCopy = NULL;
return vo;
}
VProperty* VConverter::readFieldHeader(wchar_t* buffer) {
wchar_t* headerIndex = NULL;
wchar_t* quotaIndex = NULL;
quotaIndex = wcschr(buffer, '"');
headerIndex = wcschr(buffer, ':');
if(!headerIndex)
return NULL;
bool quota = false;
// If the header contains a quotation mark,
// then rescan it starting directly after the _quotation mark_
// (not after the end of the header, as in the original code)
// to find the real end of the header.
//
// The reason for this code apparently is that the simple search above
// might have found a headerIndex which points into the middle of
// the quoted string.
//
// A better solution would be to always scan the header properly.
if(quotaIndex && quotaIndex < headerIndex) {
quota = true;
int len = int(wcslen(buffer));
for(int i = int(quotaIndex - buffer) + 1; i < len; i++) {
if(buffer[i] == '"')
quota = !quota;
if(buffer[i] == ':' && !quota) {
headerIndex = &buffer[i];
break;
}
}
}
if(quota)
return NULL;
VProperty* prop = new VProperty(NULL);
wchar_t* header = new wchar_t[wcslen(buffer) + 1];
buffer[headerIndex - buffer] = '\0';
wcscpy(header, buffer);
// Shift the remaing string to the front of the buffer.
// Using wcscpy() for that is incorrect because the standard
// does not guarantee in which order bytes are moved!
// wcscpy(buffer, ++headerIndex);
++headerIndex;
memmove(buffer, headerIndex, (wcslen(headerIndex) + 1) * sizeof(*headerIndex));
//if the header is folded (in .ics files)
//we need to remove the folding
wchar_t* headerFolding = NULL;
if((headerFolding = wcsstr(header, TEXT("\n "))) != NULL) {
header[headerFolding - header] = '\0';
}
wchar_t seps[] = TEXT(";");
wchar_t *token;
bool first = true;
token = wcstok( header, seps );
while( token != NULL ) {
if (first) {
wchar_t* group = new wchar_t[wcslen(token) + 1];
if(extractGroup(token, group))
prop->addParameter(TEXT("GROUP"), group);
else
delete [] group; group= NULL;
prop->setName(token);
first = false;
}
else {
wchar_t* paramIndex;
paramIndex = wcschr(token, '=');
if(paramIndex) {
wchar_t* paramName = new wchar_t[wcslen(token) + 1];
token[paramIndex - token] = '\0';
wcscpy(paramName, token);
++paramIndex;
memmove(token, paramIndex, (wcslen(paramIndex) + 1) * sizeof(*paramIndex));
wchar_t* paramVal = new wchar_t[wcslen(token) + 1];
wcscpy(paramVal, token);
prop->addParameter(paramName, paramVal);
delete [] paramName; paramName = NULL;
delete [] paramVal; paramVal = NULL;
}
else {
prop->addParameter(token,NULL);
}
}
token = wcstok( NULL, seps );
}
delete [] header; header = NULL;
delete token; token = NULL;
return prop;
}
bool VConverter::readFieldBody(VObject &vo, wchar_t* buffer, VProperty* vprop) {
// old folding (vCard 2.1): folding insert CRLF before _existing_ space
// new MIME folding( vCard 3.0, iCalendar): folding inserts CRLFSP
bool isOldFolding = vo.getVersion() &&
!bstrcmp(vo.getVersion(), "2.1");
bool folding = false;
wchar_t *c = buffer;
int i = 0, j = 0;
wchar_t* value = new wchar_t[wcslen(buffer) + 1];
wcscpy(value, TEXT(""));
if(vprop->equalsEncoding(TEXT("QUOTED-PRINTABLE"))) {
bool afterEqual = false;
while (c[i] != '\0') {
if (c[i] == '\r') {
if (c[i + 1] == '\n') {
if (!afterEqual) {
// end of property after \r\n,
// ignore last two characters and stop
i += 2;
break;
}
}
} else if (c[i] == '\n') {
if (!afterEqual) {
// end of property after single \n,
// ignore last two characters and stop
i += 1;
break;
}
} else if (c[i] == '=') {
afterEqual = true;
} else {
// normal character
afterEqual = false;
}
value[j] = c[i];
j++;
i++;
}
} else {
while (c[i] != '\0') {
if(folding) {
if((c[i] == ' ') || c[i] == '\t' ) {
if (isOldFolding) {
value[j] = c[i];
j++;
}
folding = false;
}
else
if((c[i] != '\r') && (c[i] != '\n'))
break;
}
else {
if((c[i] == '\r') || c[i] == '\n' )
folding = true;
else {
value[j] = c[i];
j++;
value[j] = '\0';
}
}
i++;
}
}
value[j] = 0;
vprop->setValue(value);
delete [] value; value = NULL;
// wcscpy only valid for non-overlapping buffers.
// This one here can overlap.
// wcscpy(buffer, c+i);
memmove(buffer, c+i, (wcslen(c+i) + 1) * sizeof(*c));
return true;
}
wchar_t* VConverter::extractObjectProperty(wchar_t* buffer, const wchar_t *property,
wchar_t * &buffCopy, size_t &buffCopyLen) {
// Memory handling in extractObjectType() and
// extractObjectVersion() was broken:
// they allocated a buffer, then returned a pointer into
// parts of this buffer as result. The caller cannot
// free the result in this case. The functions were also
// duplicating the same code.
//
// This partial fix reuses previously allocated
// memory if the function is called a second time.
size_t len = wcslen(buffer) + 1;
if (buffCopyLen < len) {
if (buffCopy) {
delete [] buffCopy;
}
buffCopy = new wchar_t[len];
buffCopyLen = len;
}
wcscpy(buffCopy, buffer);
wchar_t seps[] = TEXT(":\n");
wchar_t *token;
token = wcstok( buffCopy, seps );
while (token != NULL) {
if(!wcscmp(token, TEXT(property))) {
token = wcstok( NULL, seps );
wchar_t* index = wcschr(token,'\r');
if(index)
token[index-token] = '\0';
return token;
}
token = wcstok( NULL, seps );
}
return NULL;
}
wchar_t* VConverter::extractObjectType(wchar_t* buffer) {
static wchar_t* buffCopy;
static size_t buffCopyLen;
return extractObjectProperty(buffer, "BEGIN",
buffCopy, buffCopyLen);
}
wchar_t* VConverter::extractObjectVersion(wchar_t* buffer) {
static wchar_t* buffCopy;
static size_t buffCopyLen;
return extractObjectProperty(buffer, "VERSION",
buffCopy, buffCopyLen);
}
bool VConverter::extractGroup(wchar_t* propertyName, wchar_t* propertyGroup) {
wchar_t* groupIndex;
groupIndex = wcschr(propertyName, '.');
if(!groupIndex)
return false;
propertyName[groupIndex - propertyName] = '\0';
wcscpy(propertyGroup, propertyName);
wcscpy(propertyName, ++groupIndex);
return true;
}
};

View file

@ -1,32 +0,0 @@
#ifndef INCL_VIRTUAL_CONVERTER
#define INCL_VIRTUAL_CONVERTER
#include "VObject.h"
namespace vocl {
class VConverter{
public:
static VObject* parse(char* buffer);
private:
static VProperty* readFieldHeader(char* buffer);
static bool readFieldBody(VObject &vo, char* buffer, VProperty* property);
// Extract the parameter of certain properties, e.g. "BEGIN:" or "VERSION:".
// The result is a pointer into buffCopy, which is expected to have
// buffCopyLen wchars and will be reallocated if necessary.
static char* extractObjectProperty(char* buffer, const char *property,
char * &buffCopy, size_t &buffCopyLen);
// extractObjectType() and extractObjectVersion() contain static buffers,
// copy the result before calling these functions again!
static char* extractObjectType(char* buffer);
static char* extractObjectVersion(char* buffer);
static bool extractGroup(char* propertyName, char* propertyGroup);
};
};
#endif

View file

@ -1,485 +0,0 @@
/**
* Copyright (C) 2003-2006 Funambol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
// this code originally comes from the client library
// and needs some of the internal defines in
// posixadapter.h
#include "posixadapter.h"
#include "base/util/utils.h"
#include "base/util/WString.h"
#include "base/Log.h"
#include "VObject.h"
namespace vocl {
VObject::VObject() {
productID = NULL;
version = NULL;
properties = new ArrayList();
}
VObject::~VObject() {
if (productID) {
delete [] productID; productID = NULL;
}
if (version) {
delete [] version; version = NULL;
}
if (properties) {
delete properties; properties = NULL;
}
}
void VObject::set(wchar_t** p, const wchar_t* v) {
if (*p) {
delete [] *p;
}
*p = (v) ? wstrdup(v) : NULL;
}
void VObject::setVersion(const wchar_t* ver) {
set(&version, ver);
}
void VObject::setProdID(const wchar_t* prodID) {
set(&productID, prodID);
}
wchar_t* VObject::getVersion() {
return version;
}
wchar_t* VObject::getProdID() {
return productID;
}
void VObject::addProperty(VProperty* vProp) {
properties->add((ArrayElement&) *vProp);
}
int VObject::propertiesCount() {
return properties->size();
}
bool VObject::removeProperty(int index) {
if(index < 0 || index >= propertiesCount())
return false;
properties->removeElementAt(index);
return true;
}
void VObject::removeProperty(const wchar_t* propName) {
for (int i=0; i<properties->size(); i++) {
VProperty *property;
property = (VProperty* )properties->get(i);
if(!wcscmp(property->getName(), propName)) {
properties->removeElementAt(i);
break;
}
}
}
bool VObject::containsProperty(const wchar_t* propName) {
for (int i=0; i<properties->size(); i++) {
VProperty *property;
property = (VProperty* )properties->get(i);
if(!wcscmp(property->getName(), propName)) {
return true;
}
}
return false;
}
VProperty* VObject::getProperty(int index) {
return (VProperty*)properties->get(index);
}
VProperty* VObject::getProperty(const wchar_t* propName) {
for (int i=0; i<properties->size(); i++) {
VProperty *property;
property = (VProperty* )properties->get(i);
if(!wcscmp(property->getName(), propName)) {
return property;
}
}
return NULL;
}
wchar_t* VObject::toString() {
WString strVObject;
const wchar_t* eof;
// vcard 2.1 and 3.0 both use \r\n as line ending
eof = TEXT("\r\n");
for (int i=0; i<properties->size(); i++) {
VProperty *property;
property = (VProperty*)properties->get(i);
if(property->containsParameter(TEXT("GROUP"))) {
strVObject.append(property->getParameterValue(TEXT("GROUP")));
strVObject.append(TEXT("."));
property->removeParameter(TEXT("GROUP"));
}
strVObject.append(property->getName());
for(int k=0; k<property->parameterCount(); k++) {
strVObject.append(TEXT(";"));
wchar_t* paramName = new wchar_t[wcslen(property->getParameter(k))+1];
wcscpy(paramName, property->getParameter(k));
strVObject.append(paramName);
const wchar_t *value = property->getParameterValue(k);
if(value) {
strVObject.append(TEXT("="));
strVObject.append(value);
}
delete [] paramName; paramName = NULL;
}
strVObject.append(TEXT(":"));
if(property->getValue()) {
if(property->equalsEncoding(TEXT("BASE64"))) {
wchar_t delim[] = TEXT("\r\n ");
int fold = 76;
int sizeOfValue = int(wcslen(property->getValue()));
int size = sizeOfValue + (int)(sizeOfValue/fold + 2)*int(wcslen(delim));
int index = 0;
wchar_t* output = new wchar_t[size + 1];
wcscpy(output, TEXT("\0"));
while (index<sizeOfValue)
{
wcscat(output,delim);
wcsncat(output,property->getValue()+index,fold);
index+=fold;
}
strVObject.append(output);
// the extra empty line is needed because the Bachus-Naur
// specification of vCard 2.1 says so
strVObject.append(eof);
delete [] output;
}
else
strVObject.append(property->getValue());
}
strVObject.append(eof);
}
// memory must be free by caller with delete []
wchar_t *str = new wchar_t[strVObject.length() + 1];
wcscpy(str, strVObject.c_str());
return str;
}
void VObject::insertProperty(VProperty* property) {
if (propertiesCount() == 0 || wcscmp(getProperty(propertiesCount()-1)->getName(),TEXT("END")))
addProperty(property);
else {
VProperty* lastProperty = getProperty(TEXT("END"));
removeProperty(TEXT("END"));
addProperty(property);
addProperty(lastProperty);
}
}
void VObject::addFirstProperty(VProperty* property) {
properties->add(0,(ArrayElement&)*property);
}
void VObject::removeAllProperies(const wchar_t* propName) {
for(int i = 0, m = propertiesCount(); i < m ; i++)
if(!wcscmp(getProperty(i)->getName(), propName)) {
removeProperty(i);
--i;
--m;
}
}
// Patrick Ohly: hack below, see header file
static int hex2int( wchar_t x )
{
return (x >= '0' && x <= '9') ? x - '0' :
(x >= 'A' && x <= 'F') ? x - 'A' + 10 :
(x >= 'a' && x <= 'f') ? x - 'a' + 10 :
0;
}
void VObject::toNativeEncoding()
{
bool is_30 = !wcscmp(getVersion(), TEXT("3.0"));
// line break is encoded with either one or two
// characters on different platforms
const int linebreaklen = wcslen(SYNC4J_LINEBREAK);
for (int index = propertiesCount() - 1; index >= 0; index--) {
VProperty *vprop = getProperty(index);
wchar_t *name = vprop->getName();
wchar_t *foreign = vprop->getValue();
// the native encoding is always shorter than the foreign one
wchar_t *native = new wchar_t[wcslen(foreign) + 1];
if (vprop->equalsEncoding(TEXT("QUOTED-PRINTABLE"))) {
int in = 0, out = 0;
wchar_t curr;
// this is a very crude quoted-printable decoder,
// based on Wikipedia's explanation of quoted-printable
while ((curr = foreign[in]) != 0) {
in++;
if (curr == '=') {
wchar_t values[2];
values[0] = foreign[in];
in++;
if (!values[0]) {
// incomplete?!
break;
}
values[1] = foreign[in];
in++;
if (values[0] == '\r' && values[1] == '\n') {
// soft line break, ignore it
} else {
native[out] = (hex2int(values[0]) << 4) |
hex2int(values[1]);
out++;
// replace \r\n with \n?
if ( linebreaklen == 1 &&
out >= 2 &&
native[out - 2] == '\r' &&
native[out - 1] == '\n' ) {
native[out - 2] = SYNC4J_LINEBREAK[0];
out--;
}
// the conversion to wchar on Windows is
// probably missing here
}
} else {
native[out] = curr;
out++;
}
}
native[out] = 0;
out++;
} else {
wcscpy(native, foreign);
}
// decode escaped characters after backslash:
// \n is line break only in 3.0
wchar_t curr;
int in = 0, out = 0;
while ((curr = native[in]) != 0) {
in++;
switch (curr) {
case '\\':
curr = native[in];
in++;
switch (curr) {
case 'n':
if (is_30) {
// replace with line break
wcsncpy(native + out, SYNC4J_LINEBREAK, linebreaklen);
out += linebreaklen;
} else {
// normal escaped character
native[out] = curr;
out++;
}
break;
case 0:
// unexpected end of string
break;
default:
// just copy next character
native[out] = curr;
out++;
break;
}
break;
case ';':
// Might be field separator, but beware:
// in vCard 2.1 a single, unescaped semicolon is valid in all
// properties which are single values and not structured.
// Some encoders even do that in 3.0, so always accept a literal
// ; as it is in properties which are not multi-value.
if (!wcsicmp(name, "N") ||
!wcsicmp(name, "ADR") ||
!wcsicmp(name, "ORG")) {
// must replace with something special
// so that we can encode it again in fromNativeEncoding()
native[out] = SEMICOLON_REPLACEMENT;
out++;
} else {
// copy literally
native[out] = ';';
out++;
}
break;
default:
native[out] = curr;
out++;
}
}
native[out] = 0;
out++;
// charset handling:
// - doesn't exist at the moment, vCards have to be in ASCII or UTF-8
// - an explicit CHARSET parameter is removed because its parameter
// value might differ between 2.1 and 3.0 (quotation marks allowed in
// 3.0 but not 2.1) and thus would require extra code to convert it;
// when charsets really get supported this needs to be addressed
wchar_t *charset = vprop->getParameterValue(TEXT("CHARSET"));
if (charset) {
// proper decoding of the value and the property value text
// would go here, for the time being we just remove the
// value
if (_wcsicmp(charset, TEXT("UTF-8")) &&
_wcsicmp(charset, TEXT("\"UTF-8\""))) {
// log error("ignoring unsupported charset");
}
vprop->removeParameter(TEXT("CHARSET"));
}
vprop->setValue(native);
delete [] native;
}
}
void VObject::fromNativeEncoding()
{
bool is_30 = !wcscmp(getVersion(), TEXT("3.0"));
for (int index = propertiesCount() - 1; index >= 0; index--) {
VProperty *vprop = getProperty(index);
wchar_t *native = vprop->getValue();
// in the worst case every comma/linebreak is replaced with
// two characters and each \n with =0D=0A
wchar_t *foreign = new wchar_t[6 * wcslen(native) + 1];
wchar_t curr;
int in = 0, out = 0;
// line break is encoded with either one or two
// characters on different platforms
const int linebreaklen = wcslen(SYNC4J_LINEBREAK);
// use backslash for special characters,
// if necessary do quoted-printable encoding
bool doquoted = !is_30 &&
wcsstr(native, SYNC4J_LINEBREAK) != NULL;
if (vprop->equalsEncoding(TEXT("QUOTED-PRINTABLE"))) {
// remove it, recreate if doing 2.1
vprop->removeParameter(TEXT("ENCODING"));
if (!is_30) {
doquoted = true;
}
}
// non-ASCII character encountered
bool utf8 = false;
while ((curr = native[in]) != 0) {
in++;
switch (curr) {
case ',':
if (!is_30) {
// normal character
foreign[out] = curr;
out++;
break;
}
// no break!
case ';':
case '\\':
foreign[out] = '\\';
out++;
foreign[out] = curr;
out++;
break;
case SEMICOLON_REPLACEMENT:
foreign[out] = ';';
out++;
break;
default:
bool currIsUTF8 = (unsigned char)curr >= 128;
if (currIsUTF8) {
utf8 = true;
if (!is_30 && !doquoted) {
// vCard 2.1 defaults to 7-bit; instead of
// overriding that we fall back to quoted-printable
doquoted = true;
}
}
if (doquoted &&
(curr == '=' || currIsUTF8)) {
// escape = and non-ASCII characters
wsprintf(foreign + out, TEXT("=%02X"), (unsigned int)(unsigned char)curr);
out += 3;
} else if (!wcsncmp(native + in - 1,
SYNC4J_LINEBREAK,
linebreaklen)) {
// line break
if (is_30) {
foreign[out] = '\\';
out++;
foreign[out] = 'n';
out++;
} else {
wcscpy(foreign + out, TEXT("=0D=0A"));
out += 6;
}
in += linebreaklen - 1;
} else {
foreign[out] = curr;
out++;
}
break;
}
}
foreign[out] = 0;
vprop->setValue(foreign);
delete [] foreign;
if (doquoted) {
// we have used quoted-printable encoding
vprop->addParameter(TEXT("ENCODING"), TEXT("QUOTED-PRINTABLE"));
}
if (utf8 &&
!is_30 &&
!vprop->getParameterValue("CHARSET")) {
vprop->addParameter("CHARSET", "UTF-8");
}
}
}
};

View file

@ -1,88 +0,0 @@
#ifndef INCL_VIRTUAL_OBJECT
#define INCL_VIRTUAL_OBJECT
#include "VProperty.h"
namespace vocl {
class VObject {
private:
char* version;
char* productID;
ArrayList* properties;
void set(char**, const char*);
public:
VObject();
~VObject();
void setVersion (const char* ver);
void setProdID (const char* prodID);
char* getVersion();
char* getProdID();
void addProperty(VProperty* property);
void addProperty(const char *name, const char *value) { VProperty vprop(name, value); addProperty(&vprop); }
void addFirstProperty(VProperty* property);
void insertProperty(VProperty* property);
bool removeProperty(int index);
void removeProperty(const char* propName);
void removeAllProperies(const char* propName);
//removes all properties having name - propName;
bool containsProperty(const char* propName);
int propertiesCount();
VProperty* getProperty(int index);
VProperty* getProperty(const char* propName);
char* toString();
// Patrick Ohly:
//
// Normally the class does not change the encoding
// of properties. That means that users of this class
// have to be prepared to handle e.g. quoted-printable
// encoding of non-ASCII characters or \n as line break
// in vCard 3.0.
//
// This function decodes all property strings into the
// native format. It supports:
// - decoding quoted-printable characters if
// ENCODING=QUOTED-PRINTABLE
// - replacement of \n with a line break and \, with
// single comma if version is 3.0
//
// It does not support charset conversions, so everything
// has to be UTF-8 to work correctly.
//
// This function does not modify the property parameters,
// so one could convert back into the original format.
//
// Consider this function a hack: at this time it is not
// clear how the class is supposed to handle different
// encodings, but I needed a solution, so here it is.
//
void toNativeEncoding();
//
// Converts properties in native format according to
// their parameters.
//
// It only supports:
// - replacement of line breaks and commas (if 3.0)
//
// It does not support any charsets or encoding.
// ENCODING=QUOTED-PRINTABLE will be removed because
// it no longer applies when toNativeEncoding() was
// used before, but the other parameters are preserved:
// this might be good enough to recreate the original
// object.
//
void fromNativeEncoding();
/** in native property values this special character separates sub-values in multi-value properties */
static const char SEMICOLON_REPLACEMENT = '\a';
};
};
#endif

View file

@ -1,296 +0,0 @@
/**
* Copyright (C) 2003-2006 Funambol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include "posixadapter.h"
#include "base/util/utils.h"
#include "base/util/StringBuffer.h"
#include "VProperty.h"
namespace vocl {
VProperty::VProperty(const wchar_t* propname, const wchar_t* propvalue) {
name = (propname) ? wstrdup(propname) : NULL;
value = (propvalue) ? wstrdup(propvalue) : NULL;
parameters = new ArrayList();
}
VProperty::~VProperty() {
if (name) {
delete [] name; name = NULL;
}
if (value) {
delete [] value; value = NULL;
}
if (parameters) {
delete parameters; parameters = NULL;
}
}
void VProperty::setName (const wchar_t* s) {
set(&name, s);
}
void VProperty::setValue (const wchar_t* s) {
set(&value, s);
}
wchar_t* VProperty::getName(wchar_t* buf, int size) {
if (buf == NULL) {
return name;
}
if (size >= 0) {
wcsncpy(buf, name, size);
}
else {
wcscpy(buf, name);
}
return buf;
}
wchar_t* VProperty::getValue(wchar_t* buf, int size) {
if (buf == NULL) {
return value;
}
if (size >= 0) {
wcsncpy(buf, value, size);
}
else {
wcscpy(buf, value);
}
return buf;
}
void VProperty::addParameter (const wchar_t* paramName, const wchar_t* paramValue) {
if(paramName) {
WKeyValuePair *parameter = new WKeyValuePair(paramName, paramValue);
parameters->add((ArrayElement &)*parameter);
delete parameter; parameter = NULL;
}
}
void VProperty::removeParameter(const wchar_t* paramName) {
if (parameters != NULL) {
for (int i=0; i<parameters->size(); i++){
WKeyValuePair *parameter;
parameter = (WKeyValuePair* )parameters->get(i);
if(!wcscmp(parameter->getKey(), paramName)) {
parameters->removeElementAt(i);
break;
}
}
}
}
void VProperty::removeParameter(int index) {
parameters->removeElementAt(index);
}
bool VProperty::containsParameter(const wchar_t* paramName) {
if (parameters != NULL) {
for (int i=0; i<parameters->size(); i++){
WKeyValuePair *parameter;
parameter = (WKeyValuePair* )parameters->get(i);
if(!wcscmp(parameter->getKey(), paramName)){
return true;
}
}
}
return false;
}
wchar_t* VProperty::getParameterValue(const wchar_t* paramName) {
if (parameters != NULL) {
for (int i=0; i<parameters->size(); i++) {
WKeyValuePair *parameter;
parameter = (WKeyValuePair* )parameters->get(i);
if(!wcscmp(parameter->getKey(), paramName))
return ((wchar_t *)parameter->getValue());
}
}
return NULL;
}
wchar_t* VProperty::getParameterValue(int index) {
if (parameters != NULL) {
WKeyValuePair *parameter;
parameter = (WKeyValuePair*)parameters->get(index);
return parameter ? (wchar_t *)parameter->getValue() : NULL;
}
return NULL;
}
void VProperty::set(wchar_t** p, const wchar_t* v) {
if (*p) {
delete [] *p;
}
*p = (v) ? wstrdup(v) : NULL;
}
ArrayElement* VProperty::clone() {
if(name) {
VProperty *cloneProperty = new VProperty(name);
if(value)
cloneProperty->setValue(value);
if (parameters != NULL) {
for (int i=0; i<parameters->size(); i++) {
WKeyValuePair* parameterCopy;
parameterCopy = (WKeyValuePair*)parameters->get(i)->clone();
cloneProperty->addParameter(parameterCopy->getKey(), parameterCopy->getValue());
delete parameterCopy;
}
}
return cloneProperty;
}
return NULL;
}
int VProperty::parameterCount() {
return parameters->size();
}
wchar_t* VProperty::toString() {
wchar_t *propertyString = new wchar_t[VPROPETY_BUFFER];
if (name!=NULL){
wcscpy(propertyString, name);
if(parameterCount()>0) {
for (int i=0; i<parameters->size(); i++) {
WKeyValuePair *parameter;
parameter = (WKeyValuePair*)parameters->get(i);
if(parameter->getKey()!= NULL) {
wcscat(propertyString, TEXT(";"));
wcscat(propertyString, parameter->getKey());
}
if(parameter->getValue()!= NULL) {
wcscat(propertyString, TEXT("="));
wcscat(propertyString, parameter->getValue());
}
}
}
wcscat(propertyString, TEXT(":"));
if(value!=NULL) {
wcscat(propertyString, value);
}
}
return propertyString;
}
wchar_t* VProperty::getParameter(int index){
WKeyValuePair *parameter;
parameter = (WKeyValuePair*)parameters->get(index);
return (wchar_t *)parameter->getKey();
}
bool VProperty::equalsEncoding(const wchar_t* encoding) {
if ((encoding != NULL) && ((containsParameter(TEXT("ENCODING")) &&
!wcscmp(getParameterValue(TEXT("ENCODING")),encoding)) ||
containsParameter(encoding)))
return true;
return false;
}
wchar_t* VProperty::getPropComponent(int i) {
if (!getValue() || !wcscmp(getValue(),TEXT("")))
return NULL;
wchar_t *value = new wchar_t[wcslen(getValue()) + 1];
wchar_t* component = new wchar_t[wcslen(getValue()) + 1];
wcscpy(value, getValue());
wchar_t* componentIndex;
int j=0;
while (j < i) {
componentIndex = wcschr(value, ';');
if(componentIndex) {
value[componentIndex - value] = 0;
wcscpy(component, value);
wcscpy(value, ++componentIndex);
j++;
}
else
if(j<i-1)
return NULL;
else
return value;
}
delete [] value; value = NULL;
if(component && wcscmp(component, TEXT("")))
return component;
else
return NULL;
}
bool VProperty::isType(const wchar_t* type) {
if(containsParameter(type))
return true;
for (int paramindex = 0;
paramindex < parameterCount();
paramindex++) {
wchar_t *value = getParameterValue(paramindex);
wchar_t *param = getParameter(paramindex);
if (value && param && !strcasecmp(param, "TYPE")) {
wchar_t seps[] = TEXT(",");
wchar_t* token;
StringBuffer buff(value);
token = wcstok((char *)buff.c_str(), seps);
while( token != NULL ) {
if(!wcscmp(type, token))
return true;
token = wcstok( NULL, seps );
}
}
}
return false;
}
};

View file

@ -1,70 +0,0 @@
/**
* Copyright (C) 2005-2006 Funambol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef INCL_VIRTUAL_PROPERTY
#define INCL_VIRTUAL_PROPERTY
#include "base/fscapi.h"
#include "base/util/WKeyValuePair.h"
#include "base/util/ArrayList.h"
namespace vocl {
#define VPROPETY_BUFFER 500
class VProperty : public ArrayElement {
private:
char* name;
char* value;
void set(char** p, const char* v);
ArrayList* parameters;
public:
VProperty(const char* propName , const char* propValue = NULL);
~VProperty();
ArrayElement* clone();
void setName (const char* name);
void setValue (const char* value);
char* getName(char* buf = NULL, int size = -1);
char* getValue(char* buf = NULL, int size = -1);
void addParameter(const char* paramName, const char* paramValue);
void removeParameter(const char* paramName);
void removeParameter(int index);
bool containsParameter(const char* paramName);
// Warning: the name does not always uniquely identify
// the parameter, some of them may occur multiple times.
// Use getParameterValue(int index) to get the value which
// corresponds to a specific parameter.
char* getParameterValue(const char* paramName);
char* getParameterValue(int index);
char* getParameter(int index);
int parameterCount();
bool equalsEncoding(const char* encoding);
char* getPropComponent(int i);
bool isType(const char* type);
char* toString();
};
};
#endif

View file

@ -1,123 +0,0 @@
/*
* Copyright (C) 2005-2006 Funambol
* Author Patrick Ohly
*/
#ifndef INCL_POSIX_ADAPTER
#define INCL_POSIX_ADAPTER
/*
* POSIX environment, configured and compiled with automake/autoconf
*/
#include <config.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
#include <string>
#include <cwchar>
#include <iostream>
// For ntoh functions
#include <netinet/in.h>
// Cygwin version of gcc does have these builtin
#ifndef __CYGWIN__
# define __declspec(x)
# define __cdecl
#endif
//#ifdef ENABLE_NLS
//# include <libintl.h>
//# define TEXT(String) gettext (String)
//#else
//# define TEXT(String) (String)
//# endif
#define TEXT(_x) _x
#define CHR(_x) _x
#define T(_x) _x
#define EXTRA_SECTION_00
#define EXTRA_SECTION_01
#define EXTRA_SECTION_02
#define EXTRA_SECTION_03
#define EXTRA_SECTION_04
#define EXTRA_SECTION_05
#define EXTRA_SECTION_06
#define BOOL int
#define TRUE 1
#define FALSE 0
#define SYNC4J_LINEBREAK "\n"
/* map wchar_t and its functions back to standard functions */
#undef wchar_t
#define wchar_t char
#undef BCHAR
typedef char BCHAR;
typedef char WCHAR;
#define bsprintf sprintf
#define bstrlen strlen
#define bstrcpy strcpy
#define bstrcat strcat
#define bstrstr strstr
#define bstrchr strchr
#define bstrrchr strrchr
#define bscanf scanf
#define bstrcmp strcmp
#define bstricmp _stricmp
#define bstrncpy strncpy
#define bstrncmp strncmp
#define bstrtol strtol
#define bstrtoul strtoul
#define wsprintf sprintf
#define _wfopen fopen
#define wprintf printf
#define fwprintf fprintf
#define wsprintf sprintf
#define swprintf sprintf
#define wcscpy strcpy
#define wcsncpy strncpy
#define wcsncmp strncmp
#define wcslen strlen
#define wcstol strtol
#define wcstoul strtoul
#define wcsstr strstr
#define wcscmp strcmp
#define wcstok strtok
inline char towlower(char x) { return tolower(x); }
inline char towupper(char x) { return toupper(x); }
#define wmemmove memmove
#define wmemcpy memcpy
#define wmemcmp memcmp
#define wmemset memset
#define wcschr strchr
#define wcsrchr strrchr
#define wcscat strcat
#define wcsncat strncat
#define _wtoi atoi
#define wcstod strtod
#define wcsicmp strcasecmp
#define _wcsicmp strcasecmp
#define _stricmp strcasecmp
/* some of the code compares NULL against integers, which
fails if NULL is defined as (void *)0 */
#undef NULL
#define NULL 0
template <class T> T min(T x, T y) { return x < y ? x : y; }
template <class T> T max(T x, T y) { return x > y ? x : y; }
#endif

View file

@ -1,152 +0,0 @@
/*
* Copyright (C) 2003-2006 Funambol
*/
/**
* This program reads one vcard from the file
* given as first parameter and applies certain
* conversions to it.
*
* The content of the file has to be ASCII or
* UTF-8 encoded.
*/
#include <stdio.h>
#include <memory>
#include "posixadapter.h"
#include "VConverter.h"
#include "base/util/utils.h"
using namespace vocl;
// very simply auto_ptr for arrays
template <class T> class auto_array {
T *m_array;
public:
auto_array(T *array = 0) : m_array(array) {}
~auto_array() { if (m_array) delete [] m_array; }
void operator = (T *array) {
if (m_array) delete [] m_array;
m_array = array;
}
operator T * () { return m_array; }
T *get() { return m_array; }
T &operator [] (int index) { return m_array[index]; }
};
int main( int argc, char **argv )
{
char *sep = TEXT("--------------- %s -----------------------\n");
char *sep2 = TEXT("-----------------------------------------------------------\n");
if (argc != 2) {
fprintf(stdout, "usage: %s <vcard file>\n", argv[0]);
return 1;
}
// read as char *
char *buffer;
size_t len;
if (!readFile(argv[1], &buffer, &len, true)) {
fprintf(stdout, "%s: reading failed", argv[1]);
}
auto_array<char> vcard(buffer);
// convert to wchar_t
auto_array<wchar_t> wvcard(toWideChar(vcard));
fwprintf(stdout, sep, TEXT("original vcard"));
fwprintf(stdout, TEXT("%s\n"), wvcard.get());
fwprintf(stdout, sep2);
fwprintf(stdout, TEXT("\n"));
// parse it
std::auto_ptr<VObject> vobj(VConverter::parse(wvcard));
if (vobj.get() == 0) {
fprintf(stdout, "VConverter::parse()failed\n");
return 1;
}
vobj->toNativeEncoding();
VProperty *fileas = vobj->getProperty(TEXT("X-EVOLUTION-FILE-AS"));
VProperty *n = vobj->getProperty(TEXT("FN"));
fwprintf(stdout,
TEXT("version: %s\nprodid: %s\nfull name: %s\nfile-as: %s\n\n"),
vobj->getVersion(),
vobj->getProdID(),
n ? n->getValue() : TEXT("<not set>"),
fileas ? fileas->getValue() : TEXT("<not set>"));
// convert into the other version, then back again
wchar_t *versions[2];
if (!wcscmp(vobj->getVersion(), TEXT("3.0"))) {
versions[0] = TEXT("2.1");
versions[1] = TEXT("3.0");
} else {
versions[0] = TEXT("3.0");
versions[1] = TEXT("2.1");
}
for (int index = 0; index < 2; index++) {
vobj->setVersion(versions[index]);
VProperty *vprop = vobj->getProperty(TEXT("VERSION"));
for (int property = vobj->propertiesCount() - 1;
property >= 0;
property--) {
VProperty *vprop = vobj->getProperty(property);
// replace 3.0 ENCODING=B with 2.1 ENCODING=BASE64 and vice versa
char *encoding = vprop->getParameterValue("ENCODING");
if (encoding &&
(!wcsicmp(TEXT("B"), encoding) || !wcsicmp(TEXT("BASE64"), encoding))) {
vprop->removeParameter("ENCODING");
vprop->addParameter("ENCODING",
!wcscmp(versions[index], TEXT("2.1")) ?
"BASE64" : "b");
}
}
vprop->setValue(versions[index]);
vobj->fromNativeEncoding();
wvcard = vobj->toString();
vobj->toNativeEncoding();
fwprintf(stdout, sep, versions[index]);
fwprintf(stdout, TEXT("%s\n"), wvcard.get());
fwprintf(stdout, sep2);
fwprintf(stdout, TEXT("\n"));
}
#if 0
// convert into validated contact
vCardConverter converter;
converter.setSource(wvcard);
Contact *contactPtr;
long errorCode;
if (!converter.convert(lastErrorMsg, &errorCode)) {
fwprintf(stdout, TEXT("converter failed: %s (%ld)\n"), lastErrorMsg, errorCode);
return 1;
}
converter.getContact(&contactPtr);
std::auto_ptr<Contact> contact(contactPtr);
wvcard = contact->toString();
fwprintf(stdout, sep, TEXT("after parsing"));
fwprintf(stdout, TEXT("%s\n"), wvcard.get());
fwprintf(stdout, sep2);
fwprintf(stdout, TEXT("\n"));
// let's see how the Contact class interprets the properties
Name *name = contact->getName();
vCardProperty *displayname = name->getDisplayName();
fwprintf(stdout,
TEXT("display name\nencoding: %s\ncharset: %s\nlanguage: %s\nvalue: %s\n\n"),
displayname->getEncoding(),
displayname->getCharset(),
displayname->getLanguage(),
displayname->getValue());
#endif
return 0;
}

View file

@ -4,9 +4,6 @@
#include <config.h>
#include <stddef.h>
#include <spds/spdsutils.h>
#include <iostream>
#include <memory>
using namespace std;
@ -67,7 +64,6 @@ int main( int argc, char **argv )
g_type_init();
#endif
resetError();
setvbuf(stderr, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);