implemented front-end based on new SyncML C++ config API

implemented the new begin/endSync() callbacks
explain the change tracking and error handling
-> copying from server works, the other way around fails, probably because of vcard 3.0 parsing problems on the server


git-svn-id: https://zeitsenke.de/svn/SyncEvolution/trunk@6 15ad00c4-1369-45f4-8270-35d70d36bdcd
This commit is contained in:
Patrick Ohly 2005-11-26 21:16:03 +00:00
parent 3a81621f3e
commit 6b09f2f6c3
11 changed files with 473 additions and 127 deletions

48
README
View file

@ -23,20 +23,23 @@ would also be possible, but is not implemented yet. As command line
parameters sync4jevolution only supports one option which specifies the
configuration file that drive the synchronization run:
sync4jevolution <server>
sync4jevolution [<server>]
The SyncML <server> has to specified. Selection of sources of
The <server> string is used to find the configuration which determines
how synchronization is going to proceed. Selection of sources of
Evolution data which are to be synchronized with that server is done
via configuration files. It is possible to configure sources without
activating their synchronization, see the "disabled" property below.
If the SyncML server is not specified, sync4jevolution lists all
available Evolution backend databases.
Progress and error messages are both sent to stdout. In case of an
error the synchronization run is aborted and sync4jevolution returns a
non-zero value. If one data source fails, synchronization of the
remaining sources is not attempted. Recovery from failed
synchronization is done by forcing a full synchronization during the
next run, i.e. by sending all items and letting the SyncML server
compare against the ones it already knows.
non-zero value. Recovery from failed synchronization is done by
forcing a full synchronization during the next run, i.e. by sending
all items and letting the SyncML server compare against the ones it
already knows.
After a successful synchronization the server's configuration file is
updated so that the next run can be done incrementally. If the
@ -113,8 +116,9 @@ Evolution contacts with the Sync4j server:
# text/x-vcard = Evolution contact data
type = text/x-vcard
# picks one of Evolution's data sources, leave empty for default
evolutionurl =
# picks one of Evolution's data sources:
# enter either the name or the full URL
evolutionsource =
# this is appended to the server's URL to identify the
# server's database
@ -139,6 +143,32 @@ If the Evolution data source requires authentication, the
this case the directory that contains the source's config.txt should
only be accessible by the user.
Tracking Changes inside Evolution
---------------------------------
The SyncML protocol requires that a client knows which items have been
added, modified and deleted since the last sync. This is supported by
the Evolution database server, albeit in a limited way:
The same function lists changes and also moves the so called "change
marker" forward. Therefore asking for changes twice in a row will only
list changes the first time and not report the same changes a second
time. sync4jevolution delays asking for changes as long as possible
and only does it when synchronization has really started. Then
if synchronization completed and items where added, modified or
deleted on behalf of the server, the change marker is moved forward.
If synchronization fails for some or all items, then sync4jevolution
cannot mark individual items for retransmission during the next
sync and forces the next sync to execute in slow mode.
The change marker that sync4jevolution uses is a string which is
composed as "sync4jevolution:<syncURL>/<name>" where <syncURL> comes
from the server config file and <name> from the source config
file. This implies that changes are tracked separately for each server
and server database that Evolution might be synchronized with.
Compiling from Source
---------------------

View file

@ -21,22 +21,12 @@ using namespace std;
#include "EvolutionContactSource.h"
class EvolutionContactItem : public SyncItem
{
public:
EvolutionContactItem( EContact *contact );
};
EvolutionContactItem::EvolutionContactItem( EContact *contact )
{
}
EvolutionContactSource::EvolutionContactSource( const string &name,
const string &changeId,
const string &id,
bool idIsName ) :
EvolutionSyncSource( name, changeId, id, idIsName ),
m_vcardFormat( EVC_FORMAT_VCARD_30 )
EVCardFormat vcardFormat ) :
EvolutionSyncSource( name, changeId, id ),
m_vcardFormat( vcardFormat )
{
}
@ -73,9 +63,9 @@ void EvolutionContactSource::open()
throw "unable to access address books";
}
ESource *source = findSource( sources, m_id, m_idIsName );
ESource *source = findSource( sources, m_id );
if (!source) {
throw string( "no such address book: " ) + m_id;
throw string(getName()) + ": no such address book: '" + m_id + "'";
}
GError *gerror = NULL;
@ -84,46 +74,70 @@ void EvolutionContactSource::open()
if (!e_book_open( m_addressbook, TRUE, &gerror) ) {
throwError( "opening address book", gerror );
}
// find all items
gptr<EBookQuery> allItemsQuery( e_book_query_any_field_contains(""), "query" );
GList *nextItem;
if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) {
throwError( "reading all items", gerror );
}
while (nextItem) {
m_allItems.push_back( (const char *)e_contact_get_const(E_CONTACT(nextItem->data),
E_CONTACT_UID) );
nextItem = nextItem->next;
}
allItemsQuery = NULL;
// scan modified items since the last instantiation
if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) {
throwError( "reading changes", gerror );
}
while (nextItem) {
EBookChange *ebc = (EBookChange *)nextItem->data;
const char *uid = (const char *)e_contact_get_const( ebc->contact, E_CONTACT_UID );
switch (ebc->change_type) {
case E_BOOK_CHANGE_CARD_ADDED:
m_newItems.push_back( uid );
break;
case E_BOOK_CHANGE_CARD_MODIFIED:
m_updatedItems.push_back( uid );
break;
case E_BOOK_CHANGE_CARD_DELETED:
m_deletedItems.push_back( uid );
break;
}
nextItem = nextItem->next;
}
}
void EvolutionContactSource::close()
int EvolutionContactSource::beginSync()
{
if (m_addressbook) {
m_isModified = false;
try {
GError *gerror = NULL;
// find all items
gptr<EBookQuery> allItemsQuery( e_book_query_any_field_contains(""), "query" );
GList *nextItem;
if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) {
throwError( "reading all items", gerror );
}
while (nextItem) {
m_allItems.push_back( (const char *)e_contact_get_const(E_CONTACT(nextItem->data),
E_CONTACT_UID) );
nextItem = nextItem->next;
}
allItemsQuery = NULL;
// scan modified items since the last instantiation
if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) {
throwError( "reading changes", gerror );
}
while (nextItem) {
EBookChange *ebc = (EBookChange *)nextItem->data;
const char *uid = (const char *)e_contact_get_const( ebc->contact, E_CONTACT_UID );
switch (ebc->change_type) {
case E_BOOK_CHANGE_CARD_ADDED:
m_newItems.push_back( uid );
break;
case E_BOOK_CHANGE_CARD_MODIFIED:
m_updatedItems.push_back( uid );
break;
case E_BOOK_CHANGE_CARD_DELETED:
m_deletedItems.push_back( uid );
break;
}
nextItem = nextItem->next;
}
} catch( ... ) {
m_hasFailed = true;
// TODO: properly set error
return 1;
}
return 0;
}
int EvolutionContactSource::endSync()
{
try {
endSyncThrow();
} catch ( ... ) {
m_hasFailed = true;
return 1;
}
return 0;
}
void EvolutionContactSource::endSyncThrow()
{
if (m_isModified) {
GError *gerror = NULL;
GList *nextItem;
// move change_id forward so that our own changes are not listed the next time
@ -131,11 +145,14 @@ void EvolutionContactSource::close()
throwError( "reading changes", gerror );
}
}
resetItems();
m_isModified = false;
}
void EvolutionContactSource::close()
{
endSyncThrow();
m_addressbook = NULL;
m_allItems.clear();
m_newItems.clear();
m_updatedItems.clear();
m_deletedItems.clear();
}
@ -192,10 +209,13 @@ int EvolutionContactSource::addItem(SyncItem& item)
throwError( string( "parsing vcard" ) + data,
NULL );
}
m_isModified = true;
} catch ( ... ) {
m_hasFailed = true;
return STC_COMMAND_FAILED;
}
return 0;
return STC_OK;
}
int EvolutionContactSource::updateItem(SyncItem& item)
@ -218,10 +238,13 @@ int EvolutionContactSource::updateItem(SyncItem& item)
throwError( string( "parsing vcard" ) + data,
NULL );
}
m_isModified = true;
} catch ( ... ) {
m_hasFailed = true;
return STC_COMMAND_FAILED;
}
return 0;
return STC_OK;
}
int EvolutionContactSource::deleteItem(SyncItem& item)
@ -232,10 +255,13 @@ int EvolutionContactSource::deleteItem(SyncItem& item)
throwError( string( "deleting contact" ) + item.getKey(),
gerror );
}
m_isModified = true;
} catch( ... ) {
m_hasFailed = true;
return STC_COMMAND_FAILED;
}
return 0;
return STC_OK;
}
const char *EvolutionContactSource::getMimeType()

View file

@ -30,16 +30,16 @@ class EvolutionContactSource : public EvolutionSyncSource
public:
/**
* Creates a new Evolution address book source.
*
* @param changeId is used to track changes in the Evolution backend;
* not specifying it implies that always all items are returned
* @param id identifies the backend; not specifying it makes this instance
* unusable for anything but listing backend databases
* @param idIsName true iff id references to the database name, otherwise its uri
*/
EvolutionContactSource( const string &name,
const string &changeId = string(""),
const string &id = string(""),
bool idIsName = false );
EVCardFormat vcardFormat = EVC_FORMAT_VCARD_30 );
virtual ~EvolutionContactSource();
//
@ -56,7 +56,9 @@ class EvolutionContactSource : public EvolutionSyncSource
virtual int addItem(SyncItem& item);
virtual int updateItem(SyncItem& item);
virtual int deleteItem(SyncItem& item);
virtual int beginSync();
virtual int endSync();
private:
/** valid after open(): the address book that this source references */
gptr<EBook, GObject> m_addressbook;
@ -66,4 +68,7 @@ class EvolutionContactSource : public EvolutionSyncSource
/** the mime type which corresponds to m_vcardFormat */
const char *getMimeType();
/** internal implementation of endSync() which will throw an exception in case of failure */
void endSyncThrow();
};

128
src/EvolutionSyncClient.cpp Normal file
View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2005 Patrick Ohly
*
* 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 "EvolutionSyncClient.h"
#include "EvolutionSyncSource.h"
#include <spdm/DMTree.h>
#include <list>
#include <memory>
#include <vector>
using namespace std;
EvolutionSyncClient::EvolutionSyncClient(const string &server) :
m_client(Sync4jClient::getInstance()),
m_server(server),
m_configPath(string("evolution/") + server)
{
m_client.setDMConfig(m_configPath.c_str());
}
EvolutionSyncClient::~EvolutionSyncClient()
{
Sync4jClient::dispose();
}
void EvolutionSyncClient::sync()
{
class sourcelist : public list<EvolutionSyncSource *> {
public:
~sourcelist() {
for( iterator it = begin();
it != end();
++it ) {
delete *it;
}
}
} sources;
DMTree config(m_configPath.c_str());
// find server URL (part of change id)
string serverPath = m_configPath + "/spds/syncml";
auto_ptr<ManagementNode> serverNode(config.getManagementNode(serverPath.c_str()));
string url = EvolutionSyncSource::getPropertyValue(*serverNode, "syncURL");
// find sources
string sourcesPath = m_configPath + "/spds/sources";
auto_ptr<ManagementNode> sourcesNode(config.getManagementNode(sourcesPath.c_str()));
int index, numSources = sourcesNode->getChildrenMaxCount();
char **sourceNamesPtr = sourcesNode->getChildrenNames();
// copy source names into format that will be
// freed in case of exception
vector<string> sourceNames;
for ( index = 0; index < numSources; index++ ) {
sourceNames.push_back(sourceNamesPtr[index]);
delete [] sourceNamesPtr[index];
}
delete [] sourceNamesPtr;
// iterate over sources
for ( index = 0; index < numSources; index++ ) {
// is the source enabled?
string sourcePath(sourcesPath + "/" + sourceNames[index]);
auto_ptr<ManagementNode> sourceNode(config.getManagementNode(sourcePath.c_str()));
string disabled = EvolutionSyncSource::getPropertyValue(*sourceNode, "disabled");
if (disabled != "T" && disabled != "t") {
// create it
string type = EvolutionSyncSource::getPropertyValue(*sourceNode, "type");
EvolutionSyncSource *syncSource =
EvolutionSyncSource::createSource(
sourceNames[index],
string("sync4jevolution:") + url + "/" + EvolutionSyncSource::getPropertyValue(*sourceNode, "name"),
EvolutionSyncSource::getPropertyValue(*sourceNode, "evolutionsource"),
type
);
if (!syncSource) {
throw sourceNames[index] + ": type " +
( type.size() ? string("not configured") :
string("'") + type + "' empty or unknown" );
}
sources.push_back(syncSource);
// also open it; failing now is still safe
syncSource->open();
}
}
if (!sources.size()) {
LOG.info( "no sources configured, done" );
return;
}
// build array as sync wants it, then sync
// (no exceptions allowed here)
SyncSource **sourceArray = new SyncSource *[sources.size() + 1];
index = 0;
for ( list<EvolutionSyncSource *>::iterator it = sources.begin();
it != sources.end();
++it ) {
sourceArray[index] = *it;
++index;
}
sourceArray[index] = NULL;
int res = m_client.sync( sourceArray );
delete [] sourceArray;
// TODO: force slow sync in case of res != STC_OK or failed Evolution source
if (res != STC_OK) {
throw lastErrorCode;
}
}

53
src/EvolutionSyncClient.h Normal file
View file

@ -0,0 +1,53 @@
/*
* Copyright (C) 2005 Patrick Ohly
*
* 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_EVOLUTIONSYNCCLIENT
#define INCL_EVOLUTIONSYNCCLIENT
#include <common/client/Sync4jClient.h>
#include <string>
using namespace std;
/*
* This is the main class inside sync4jevolution which
* looks at the configuration, activates all enabled
* sources and executes the synchronization.
*
* Despite the name it is not a Sync4jClient, but rather
* uses one.
*/
class EvolutionSyncClient {
Sync4jClient& m_client;
const string m_server;
const string m_configPath;
public:
/**
* @param server identifies the server config to be used
*/
EvolutionSyncClient(const string &server);
~EvolutionSyncClient();
/**
* executes the sync, throws an exception in case of failure
*/
void sync();
};
#endif // INCL_EVOLUTIONSYNCCLIENT

View file

@ -17,17 +17,19 @@
*/
#include "EvolutionSyncSource.h"
#include "EvolutionContactSource.h"
ESource *EvolutionSyncSource::findSource( ESourceList *list, const string &id, bool isName )
#include <common/base/Log.h>
ESource *EvolutionSyncSource::findSource( ESourceList *list, const string &id )
{
for (GSList *g = e_source_list_peek_groups (list); g; g = g->next) {
ESourceGroup *group = E_SOURCE_GROUP (g->data);
GSList *s;
for (s = e_source_group_peek_sources (group); s; s = s->next) {
ESource *source = E_SOURCE (s->data);
if ( !id.compare( isName ?
e_source_peek_name(source) :
e_source_get_uri(source) ) )
if ( !id.compare(e_source_peek_name(source)) ||
!id.compare(e_source_get_uri(source)) )
return source;
}
}
@ -44,8 +46,18 @@ void EvolutionSyncSource::throwError( const string &action, GError *gerror )
} else {
gerrorstr = ": failed";
}
throw m_id + ": " + action + gerrorstr;
string error = string(getName()) + ": " + action + gerrorstr;
LOG.error( error.c_str() );
throw error;
}
void EvolutionSyncSource::resetItems()
{
m_allItems.clear();
m_newItems.clear();
m_updatedItems.clear();
m_deletedItems.clear();
}
string EvolutionSyncSource::getData(SyncItem& item)
@ -58,3 +70,44 @@ string EvolutionSyncSource::getData(SyncItem& item)
free(mem);
return res;
}
string EvolutionSyncSource::getPropertyValue(ManagementNode &node, const string &property)
{
char *value = node.getPropertyValue(property.c_str());
string res;
if (value) {
res = value;
delete [] value;
}
return res;
}
EvolutionSyncSource *EvolutionSyncSource::createSource(
const string &name,
const string &changeId,
const string &id,
const string &mimeType
)
{
if (mimeType == "text/x-vcard") {
return new EvolutionContactSource(name, changeId, id, EVC_FORMAT_VCARD_30);
}
// TODO: other mime types?
return NULL;
}
void EvolutionSyncSource::setItemStatus(const char *key, int status)
{
if (status < 200 || status > 300) {
char buffer[200];
sprintf(buffer,
"unexpected SyncML status response %d for item %.80s\n",
status, key);
LOG.error(buffer);
m_hasFailed = true;
}
}

View file

@ -16,6 +16,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INCL_EVOLUTIONSYNCSOURCE
#define INCL_EVOLUTIONSYNCSOURCE
#include <string>
#include <vector>
#include <list>
@ -24,7 +27,8 @@ using namespace std;
#include <libedataserver/e-source.h>
#include <libedataserver/e-source-list.h>
#include <common/spds/SyncSource.h>
#include <spds/SyncSource.h>
#include <spdm/ManagementNode.h>
/**
* This class implements the functionality shared by
@ -57,9 +61,8 @@ class EvolutionSyncSource : public SyncSource
* @param changeId is used to track changes in the Evolution backend
* @param id identifies the backend; not specifying it makes this instance
* unusable for anything but listing backend databases
* @param idIsName true iff id references to the database name, otherwise its uri
*/
EvolutionSyncSource( const string name, const string &changeId, const string &id, bool idIsName ) :
EvolutionSyncSource( const string name, const string &changeId, const string &id ) :
SyncSource( name.c_str() ),
m_allItems( *this, SYNC_STATE_NONE ),
m_newItems( *this, SYNC_STATE_NEW ),
@ -67,8 +70,8 @@ class EvolutionSyncSource : public SyncSource
m_deletedItems( *this, SYNC_STATE_DELETED ),
m_changeId( changeId ),
m_hasFailed( false ),
m_id( id ),
m_idIsName( idIsName )
m_isModified( false ),
m_id( id )
{}
virtual ~EvolutionSyncSource() {}
@ -87,36 +90,13 @@ class EvolutionSyncSource : public SyncSource
virtual sources getSyncBackends() = 0;
/**
* actually opens the data source specified in the constructor,
* will throw the normal exceptions if that fails
* Actually opens the data source specified in the constructor,
* will throw the normal exceptions if that fails. Should
* not modify the state of the sync source: that can be deferred
* until the server is also ready and beginSync() is called.
*/
virtual void open() = 0;
/**
* closes the data source so that it can be reopened
*/
virtual void close() = 0;
/**
* returns true iff some failure occured
*/
bool hasFailed() { return m_hasFailed; }
//
// default implementation of SyncSource iterators
//
virtual int beginSync() { return STC_OK; }
virtual SyncItem* getFirstItem() { return m_allItems.start(); }
virtual SyncItem* getNextItem() { return m_allItems.iterate(); }
virtual SyncItem* getFirstNewItem() { return m_newItems.start(); }
virtual SyncItem* getNextNewItem() { return m_newItems.iterate(); }
virtual SyncItem* getFirstUpdatedItem() { return m_updatedItems.start(); }
virtual SyncItem* getNextUpdatedItem() { return m_updatedItems.iterate(); }
virtual SyncItem* getFirstDeletedItem() { return m_deletedItems.start(); }
virtual SyncItem* getNextDeletedItem() { return m_deletedItems.iterate(); }
virtual int endSync() { return STC_OK; }
virtual void setItemStatus(const char *key, int status) {};
/**
* Extract information for the item identified by UID
* and store it in a new SyncItem. The caller must
@ -127,19 +107,69 @@ class EvolutionSyncSource : public SyncSource
*/
virtual SyncItem *createItem( const string &uid, SyncState state ) = 0;
/**
* closes the data source so that it can be reopened
*
* Just as open() it should not affect the state of
* the database unless some previous action requires
* it.
*/
virtual void close() = 0;
/**
* resets the lists of all/new/updated/deleted items
*/
void resetItems();
/**
* returns true iff some failure occured
*/
bool hasFailed() { return m_hasFailed; }
/** convenience function: copies item's data into string */
static string getData(SyncItem& item);
/**
* convenience function: gets property as string class
*
* @return empty string if property not found, otherwise its value
*/
static string getPropertyValue(ManagementNode &node, const string &property);
/**
* factory function for a EvolutionSyncSources that provides the
* given mime type; for the other parameters see constructor
*
* @return NULL if no source can handle the given type
*/
static EvolutionSyncSource *createSource(
const string &name,
const string &changeId,
const string &id,
const string &mimeType );
//
// default implementation of SyncSource iterators
//
virtual SyncItem* getFirstItem() { return m_allItems.start(); }
virtual SyncItem* getNextItem() { return m_allItems.iterate(); }
virtual SyncItem* getFirstNewItem() { return m_newItems.start(); }
virtual SyncItem* getNextNewItem() { return m_newItems.iterate(); }
virtual SyncItem* getFirstUpdatedItem() { return m_updatedItems.start(); }
virtual SyncItem* getNextUpdatedItem() { return m_updatedItems.iterate(); }
virtual SyncItem* getFirstDeletedItem() { return m_deletedItems.start(); }
virtual SyncItem* getNextDeletedItem() { return m_deletedItems.iterate(); }
virtual void setItemStatus(const char *key, int status);
protected:
/**
* searches the list for a source with the given uri or name
*
* @param list a list previously obtained from Gnome
* @param id a string identifying the data source: either its name or uri
* @param isName id is the name, otherwise uri
* @return pointer to source or NULL if not found
*/
ESource *findSource( ESourceList *list, const string &id, bool isName );
ESource *findSource( ESourceList *list, const string &id );
/**
* throw an exception after a Gnome action failed and
@ -153,7 +183,6 @@ class EvolutionSyncSource : public SyncSource
const string m_changeId;
const string m_id;
const bool m_idIsName;
class itemList : public list<string> {
const_iterator m_it;
@ -196,5 +225,9 @@ class EvolutionSyncSource : public SyncSource
/** keeps track of failure state */
bool m_hasFailed;
/** remembers whether items have been modified during the sync */
bool m_isModified;
};
#endif // INCL_EVOLUTIONSYNCSOURCE

View file

@ -7,6 +7,7 @@ bin_PROGRAMS = sync4jevolution
CORE_SOURCES = \
EvolutionSyncSource.cpp \
EvolutionSyncClient.cpp \
EvolutionContactSource.cpp
CORE_LDADD = @EPACKAGE_LIBS@ @SYNC4J_LIBS@ @LIBS@

View file

@ -144,6 +144,7 @@ bin_PROGRAMS = sync4jevolution
CORE_SOURCES = \
EvolutionSyncSource.cpp \
EvolutionSyncClient.cpp \
EvolutionContactSource.cpp
CORE_LDADD = @EPACKAGE_LIBS@ @SYNC4J_LIBS@ @LIBS@
@ -177,7 +178,7 @@ check_PROGRAMS = test$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
am__objects_1 = EvolutionSyncSource.$(OBJEXT) \
EvolutionContactSource.$(OBJEXT)
EvolutionSyncClient.$(OBJEXT) EvolutionContactSource.$(OBJEXT)
am_sync4jevolution_OBJECTS = sync4jevolution.$(OBJEXT) $(am__objects_1)
sync4jevolution_OBJECTS = $(am_sync4jevolution_OBJECTS)
sync4jevolution_DEPENDENCIES =
@ -192,6 +193,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/EvolutionContactSource.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/EvolutionSyncClient.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/EvolutionSyncSource.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/TestEvolution.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/TestMain.Po \
@ -267,6 +269,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EvolutionContactSource.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EvolutionSyncClient.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EvolutionSyncSource.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestEvolution.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TestMain.Po@am__quote@

View file

@ -37,6 +37,7 @@
#include <EvolutionContactSource.h>
#include <common/spds/SyncStatus.h>
#include <string.h>
@ -140,8 +141,7 @@ void TestEvolution::testContactOpen()
{
EvolutionContactSource source( string( "dummy" ),
m_changeIds[0],
m_contactName,
true );
m_contactName );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
}
@ -173,10 +173,10 @@ void TestEvolution::testContactSimpleInsert()
EvolutionContactSource source(
string( "dummy" ),
m_changeIds[0],
m_contactName,
true );
m_contactName );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
int numItems;
CPPUNIT_ASSERT_NO_THROW( numItems = countItems( source ) );
SyncItem item;
@ -187,6 +187,7 @@ void TestEvolution::testContactSimpleInsert()
EVOLUTION_ASSERT_NO_THROW( source, source.close() );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
CPPUNIT_ASSERT( countItems( source ) == numItems + 1 );
CPPUNIT_ASSERT( countNewItems( source ) == 0 );
CPPUNIT_ASSERT( countUpdatedItems( source ) == 0 );
@ -206,10 +207,10 @@ void TestEvolution::testContactDeleteAll()
EvolutionContactSource source( string( "dummy" ),
m_changeIds[0],
m_contactName,
true );
m_contactName );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
int numItems = countItems( source );
CPPUNIT_ASSERT( numItems > 0 );
@ -223,6 +224,7 @@ void TestEvolution::testContactDeleteAll()
EVOLUTION_ASSERT_NO_THROW( source, source.close() );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
EVOLUTION_ASSERT_MESSAGE(
"should be empty now",
source,
@ -236,10 +238,10 @@ void TestEvolution::testContactIterateTwice()
{
EvolutionContactSource source( string( "dummy" ),
m_changeIds[0],
m_contactName,
true );
m_contactName );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
EVOLUTION_ASSERT_MESSAGE(
"iterating twice should produce identical results",
source,
@ -257,9 +259,9 @@ void TestEvolution::contactUpdate()
{
EvolutionContactSource source( string( "dummy" ),
m_changeIds[0],
m_contactName,
true );
m_contactName );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
SyncItem *item;
EVOLUTION_ASSERT_NO_THROW( source, item = source.getFirstItem() );
const char *vcard =
@ -288,6 +290,7 @@ void TestEvolution::contactUpdate()
EVOLUTION_ASSERT_NO_THROW( source, source.close() );
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
CPPUNIT_ASSERT( countItems( source ) == 1 );
CPPUNIT_ASSERT( countNewItems( source ) == 0 );
CPPUNIT_ASSERT( countUpdatedItems( source ) == 0 );
@ -315,15 +318,16 @@ void TestEvolution::testContactChanges()
EvolutionContactSource source( string( "dummy" ),
m_changeIds[1],
m_contactName,
true );
m_contactName );
// update change id #1
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
EVOLUTION_ASSERT_NO_THROW( source, source.close() );
// no new changes
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
CPPUNIT_ASSERT( countItems( source ) == 1 );
CPPUNIT_ASSERT( countNewItems( source ) == 0 );
CPPUNIT_ASSERT( countUpdatedItems( source ) == 0 );
@ -335,6 +339,7 @@ void TestEvolution::testContactChanges()
// delete item again
testContactDeleteAll();
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
CPPUNIT_ASSERT( countItems( source ) == 0 );
CPPUNIT_ASSERT( countNewItems( source ) == 0 );
CPPUNIT_ASSERT( countUpdatedItems( source ) == 0 );
@ -352,6 +357,7 @@ void TestEvolution::testContactChanges()
// insert another item
testContactSimpleInsert();
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
CPPUNIT_ASSERT( countItems( source ) == 1 );
CPPUNIT_ASSERT( countNewItems( source ) == 1 );
CPPUNIT_ASSERT( countUpdatedItems( source ) == 0 );
@ -369,6 +375,7 @@ void TestEvolution::testContactChanges()
// update item
contactUpdate();
EVOLUTION_ASSERT_NO_THROW( source, source.open() );
EVOLUTION_ASSERT( source, source.beginSync() == 0 );
CPPUNIT_ASSERT( countItems( source ) == 1 );
CPPUNIT_ASSERT( countNewItems( source ) == 0 );
CPPUNIT_ASSERT( countUpdatedItems( source ) == 1 );

View file

@ -23,6 +23,7 @@
using namespace std;
#include "EvolutionContactSource.h"
#include "EvolutionSyncClient.h"
/**
* list all known data sources of a certain type
@ -53,8 +54,12 @@ int main( int argc, char **argv )
listSources( contactSource, "address books" );
fprintf( stderr, "usage: %s <server>\n", argv[0] );
return 1;
} else {
EvolutionSyncClient client(argv[1]);
client.sync();
}
return 0;
} catch ( int sync4jerror ) {
LOG.error( lastErrorMsg );
} catch ( string *errmsg ) {
@ -62,9 +67,11 @@ int main( int argc, char **argv )
delete errmsg;
} catch ( const char *errmsg ) {
LOG.error( errmsg );
} catch ( const string error ) {
LOG.error( error.c_str() );
} catch (...) {
LOG.error( "unknown error" );
}
return 0;
return 1;
}