- implemented automatic backups, logging and database comparison
- prepared 0.2 release git-svn-id: https://zeitsenke.de/svn/SyncEvolution/trunk@57 15ad00c4-1369-45f4-8270-35d70d36bdcd
This commit is contained in:
parent
11e4fff4a7
commit
12b98e85c4
11 changed files with 481 additions and 40 deletions
20
NEWS
20
NEWS
|
@ -1,3 +1,23 @@
|
|||
SyncEvolution 0.2, 2006-03-19
|
||||
-----------------------------
|
||||
|
||||
* Added automatic backup mechanism and log storage,
|
||||
see "Automatic Backups and Logging".
|
||||
* Output no longer is the original log data, but rather
|
||||
a human-readable report of errors and synchronization
|
||||
results.
|
||||
* "normalize_vcard" can now also compare two .vcf files
|
||||
directly.
|
||||
* improved unit tests to catch more errors
|
||||
* hide certain differences in vcards coming back from
|
||||
the server: duplication of extended vcard properties,
|
||||
missing TYPE=OTHER
|
||||
* fixed client library problems:
|
||||
see http://forge.objectweb.org/tracker/?group_id=96&atid=100096
|
||||
#304792, #304829
|
||||
* added some more problems to the "Known Problems" section
|
||||
|
||||
|
||||
SyncEvolution 0.1, 2006-03-13
|
||||
-----------------------------
|
||||
|
||||
|
|
95
README
95
README
|
@ -19,7 +19,7 @@ Introduction
|
|||
SyncEvolution synchronizes Evolution's contact and calender items
|
||||
[calender not implemented yet]
|
||||
with a SyncML server. The items are exchanged in the vCard and
|
||||
vCalender formats and via the Funambol Sync4j C++ client API library,
|
||||
vCalender formats via the Funambol Sync4j C++ client API library,
|
||||
which should make SyncEvolution compatible with the majority of
|
||||
SyncML servers. Full, one-way and incremental synchronization of items
|
||||
are supported.
|
||||
|
@ -41,15 +41,7 @@ following works:
|
|||
- conflict resolution (where two clients modify the same item,
|
||||
then sync with the server) is handled by the server, but
|
||||
SyncEvolution has support which ensures that no data is lost
|
||||
by creating duplicates (see Conflict Resolution below)
|
||||
|
||||
Although all of the features are covered by unit testing and
|
||||
have been verified to work, it is highly recommended that you
|
||||
make a backup of your
|
||||
$HOME/.evolution/addressbook
|
||||
$HOME/.evolution/calender
|
||||
directories before running it for the first time. In older Evolution
|
||||
versions the same data is found in $HOME/evolution.
|
||||
by creating duplicates (see "Conflict Resolution" below)
|
||||
|
||||
|
||||
Installation
|
||||
|
@ -75,6 +67,14 @@ For Sync4j V2.3, an additional patch is recommended to preserve
|
|||
line breaks of items on the server:
|
||||
http://forge.objectweb.org/tracker/index.php?func=detail&aid=304718&group_id=96&atid=300096
|
||||
|
||||
Although all of the features are covered by unit testing and
|
||||
have been verified to work, it is highly recommended that you
|
||||
make a backup of your
|
||||
$HOME/.evolution/addressbook
|
||||
$HOME/.evolution/calender
|
||||
directories before running it for the first time. In older Evolution
|
||||
versions the same data is found in $HOME/evolution.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
@ -91,17 +91,24 @@ 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.
|
||||
activating their synchronization, see the "disabled" property.
|
||||
|
||||
If the SyncML server is not specified, SyncEvolution 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 SyncEvolution returns a
|
||||
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.
|
||||
Progress and error messages are written into a log file that is
|
||||
preserved for each synchronization run. Details about that is found
|
||||
in the "Automatic Backups and Logging" section below. Immediately
|
||||
before quitting SyncEvolution will show all errors or warnings
|
||||
encountered and print a summary of how the databases were modified.
|
||||
This is done with the "normalize_vcard" utility script described
|
||||
in the "Exchanging Data" section.
|
||||
|
||||
In case of an error the synchronization run is aborted prematurely and
|
||||
SyncEvolution will return a 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
|
||||
|
@ -161,6 +168,49 @@ this case the directory that contains the source's config.txt should
|
|||
only be accessible by the user. [NOT IMPLEMENTED YET]
|
||||
|
||||
|
||||
Automatic Backups and Logging
|
||||
-----------------------------
|
||||
|
||||
To support recovery from a synchronization which damaged the
|
||||
local database or modified it in an unexpected way, SyncEvolution
|
||||
always creates the following files during a synchronization:
|
||||
- a dump of the database in a format which can be imported
|
||||
back into Evolution, e.g. .vcf for address books
|
||||
- a full log file with debug information
|
||||
- a dump of the database after the synchronization for
|
||||
automatic comparison of the before/after state with
|
||||
"normalize_vcard"
|
||||
|
||||
If the source configuration option "logdir" is set, then
|
||||
a new directory will be created for each synchronization
|
||||
in that directory, using the format
|
||||
SyncEvolution-<server>-<yyyy>-<mm>-<dd>-<hh>-<mm>[-<seq>]
|
||||
with the various fields filled in with the time when the
|
||||
synchronization started. The sequence suffix will only be
|
||||
used when necessary to make the name unique. By default,
|
||||
SyncEvolution will never delete any data in that log
|
||||
directory unless explicitly asked to keep only a limited
|
||||
number of previous log directories.
|
||||
|
||||
This is done by setting the "maxlogdirs" limit to something
|
||||
different than the empty sring or 0: if a limit is set,
|
||||
then SyncEvolution will only keep that many log directories
|
||||
and start removing the oldest ones when it reaches the limit.
|
||||
This cleanup is only done after a successful synchronization
|
||||
and is limited to directories starting with the
|
||||
SyncEvolution-<server>
|
||||
prefix, so it is safe to put other files or directories
|
||||
into the configured log directory.
|
||||
|
||||
If that option is not set, then the directory will be
|
||||
created as
|
||||
$TMPDIR/SyncEvolution-<username>-<server>
|
||||
with access allowed for the user only. Files from a
|
||||
previous synchronization will be overwritten. This is
|
||||
a lot less useful because the data will probably
|
||||
be lost during the next reboot.
|
||||
|
||||
|
||||
Exchanging Data
|
||||
---------------
|
||||
|
||||
|
@ -282,6 +332,9 @@ and server database that Evolution might be synchronized with.
|
|||
Known Problems
|
||||
--------------
|
||||
|
||||
ObjectWeb #<num> refers to the Funambol issue tracker at:
|
||||
http://forge.objectweb.org/tracker/?group_id=96&atid=100096
|
||||
|
||||
- Evolution 2.0.4 and 2.4.2.1 still display the old content of a contact
|
||||
which was updated during a certain test (TestEvolution::testMerge).
|
||||
Exact reason unknown, needs to be investigated.
|
||||
|
@ -294,6 +347,8 @@ Known Problems
|
|||
assertion failed
|
||||
- Expression: !res
|
||||
|
||||
ObjectWeb #304806
|
||||
|
||||
- various vcard and special character related problems in the
|
||||
Sync4j server and client library:
|
||||
TestEvolution::testVCard fails the check that items
|
||||
|
@ -305,6 +360,12 @@ Known Problems
|
|||
Characters with special meaning in XML like & < > cannot be
|
||||
exchanged.
|
||||
|
||||
ObjectWeb #304828, #304786, #304784, #304782
|
||||
|
||||
- error handling could be improved
|
||||
|
||||
ObjectWeb #304805, #304562
|
||||
|
||||
- Removing a field and then synchronizing with the Sync4j server
|
||||
will not remove that field on the server. The server will preserve
|
||||
the old value instead.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_INIT(src/syncevolution.cpp)
|
||||
AM_INIT_AUTOMAKE(syncevolution, 0.1)
|
||||
AM_INIT_AUTOMAKE(syncevolution, 0.2)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
AC_ARG_WITH(sync4j,
|
||||
|
|
|
@ -21,6 +21,19 @@ useProxy = F
|
|||
# proxy URL (http://<host>:<port>)
|
||||
proxyHost =
|
||||
|
||||
# full path to directory where automatic backups and logs
|
||||
# are stored for all synchronizations; if empty, the temporary
|
||||
# directory "$TMPDIR/SyncEvolution-<username>-<server>" will
|
||||
# be used to keep the data of just the latest synchronization run
|
||||
logdir =
|
||||
|
||||
# Unless this option is set, SyncEvolution will never delete
|
||||
# anything in the "logdir". If set, the oldest directories and
|
||||
# all their content will be removed after a successful sync
|
||||
# to prevent the number of log directories from growing beyond
|
||||
# the given limit.
|
||||
maxlogdirs =
|
||||
|
||||
# used by the SyncML library internally; do not modify
|
||||
begin =
|
||||
end =
|
||||
|
|
|
@ -220,7 +220,6 @@ int EvolutionContactSource::endSync()
|
|||
|
||||
void EvolutionContactSource::endSyncThrow()
|
||||
{
|
||||
LOG.info( m_isModified ? "EvolutionContactSource: address book was modified" : "EvolutionContactSource: no modifications" );
|
||||
if (m_isModified) {
|
||||
GError *gerror = NULL;
|
||||
GList *nextItem;
|
||||
|
|
|
@ -62,6 +62,7 @@ class EvolutionContactSource : public EvolutionSyncSource
|
|||
virtual void open();
|
||||
virtual void close();
|
||||
virtual void exportData(ostream &out);
|
||||
virtual string fileSuffix() { return "vcf"; }
|
||||
|
||||
virtual SyncItem *createItem( const string &uid, SyncState state );
|
||||
|
||||
|
|
|
@ -20,17 +20,29 @@
|
|||
#include "EvolutionSyncSource.h"
|
||||
|
||||
#include <spdm/DMTree.h>
|
||||
#include <posix/base/posixlog.h>
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
EvolutionSyncClient::EvolutionSyncClient(const string &server) :
|
||||
m_client(Sync4jClient::getInstance()),
|
||||
m_server(server),
|
||||
m_configPath(string("evolution/") + server)
|
||||
{
|
||||
LOG.setLevel(LOG_LEVEL_INFO);
|
||||
m_client.setDMConfig(m_configPath.c_str());
|
||||
}
|
||||
|
||||
|
@ -39,18 +51,318 @@ EvolutionSyncClient::~EvolutionSyncClient()
|
|||
Sync4jClient::dispose();
|
||||
}
|
||||
|
||||
void EvolutionSyncClient::sync( SyncMode syncMode )
|
||||
/// remove all files in the given directory and the directory itself
|
||||
static void rmBackupDir(const string &dirname)
|
||||
{
|
||||
class sourcelist : public list<EvolutionSyncSource *> {
|
||||
public:
|
||||
~sourcelist() {
|
||||
for( iterator it = begin();
|
||||
it != end();
|
||||
++it ) {
|
||||
delete *it;
|
||||
DIR *dir = opendir(dirname.c_str());
|
||||
if (!dir) {
|
||||
throw dirname + ": " + strerror(errno);
|
||||
}
|
||||
vector<string> entries;
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
entries.push_back(entry->d_name);
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
for (vector<string>::iterator it = entries.begin();
|
||||
it != entries.end();
|
||||
++it) {
|
||||
string path = dirname + "/" + *it;
|
||||
if (unlink(path.c_str())
|
||||
&& errno != ENOENT
|
||||
#ifdef EISDIR
|
||||
&& errno != EISDIR
|
||||
#endif
|
||||
) {
|
||||
throw path + ": " + strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (rmdir(dirname.c_str())) {
|
||||
throw dirname + ": " + strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
// this class owns the logging directory and is responsible
|
||||
// for redirecting output at the start and end of sync (even
|
||||
// in case of exceptions thrown!)
|
||||
class LogDir {
|
||||
string m_logdir; /**< configured backup root dir, empty if none */
|
||||
int m_maxlogdirs; /**< number of backup dirs to preserve, 0 if unlimited */
|
||||
string m_prefix; /**< common prefix of backup dirs */
|
||||
string m_path; /**< path to current logging and backup dir */
|
||||
string m_logfile; /**< path to log file there */
|
||||
const string &m_server; /**< name of the server for this synchronization */
|
||||
|
||||
public:
|
||||
LogDir(const string &server) : m_server(server) {}
|
||||
|
||||
// setup log directory and redirect logging into it
|
||||
// @param path path to configured backup directy, NULL if defaulting to /tmp
|
||||
// @param maxlogdirs number of backup dirs to preserve in path, 0 if unlimited
|
||||
void setLogdir(const char *path, int maxlogdirs) {
|
||||
m_maxlogdirs = maxlogdirs;
|
||||
if (path && path[0]) {
|
||||
m_logdir = path;
|
||||
|
||||
// create unique directory name in the given directory
|
||||
time_t ts = time(NULL);
|
||||
struct tm *tm = localtime(&ts);
|
||||
stringstream base;
|
||||
// SyncEvolution-<server>-<yyyy>-<mm>-<dd>-<hh>-<mm>
|
||||
m_prefix = "SyncEvolution-";
|
||||
m_prefix += m_server;
|
||||
base << path << "/"
|
||||
<< m_prefix
|
||||
<< "-"
|
||||
<< setfill('0')
|
||||
<< setw(4) << tm->tm_year + 1900 << "-"
|
||||
<< setw(2) << tm->tm_mon << "-"
|
||||
<< tm->tm_mday << "-"
|
||||
<< tm->tm_hour << "-"
|
||||
<< tm->tm_min;
|
||||
int seq = 0;
|
||||
while (true) {
|
||||
stringstream path;
|
||||
path << base.str();
|
||||
if (seq) {
|
||||
path << "-" << seq;
|
||||
}
|
||||
m_path = path.str();
|
||||
if (!mkdir(m_path.c_str(), S_IRWXU)) {
|
||||
break;
|
||||
}
|
||||
if (errno != EEXIST) {
|
||||
throw m_path + ": " + strerror(errno);
|
||||
}
|
||||
seq++;
|
||||
}
|
||||
} else {
|
||||
// create temporary directory: $TMPDIR/SyncEvolution-<username>
|
||||
stringstream path;
|
||||
char *tmp = getenv("TMPDIR");
|
||||
if (tmp) {
|
||||
path << tmp;
|
||||
} else {
|
||||
path << "/tmp";
|
||||
}
|
||||
path << "/SyncEvolution-";
|
||||
struct passwd *user = getpwuid(getuid());
|
||||
if (user && user->pw_name) {
|
||||
path << user->pw_name;
|
||||
} else {
|
||||
path << getuid();
|
||||
}
|
||||
path << "-" << m_server;
|
||||
|
||||
m_path = path.str();
|
||||
if (mkdir(m_path.c_str(), S_IRWXU)) {
|
||||
if (errno != EEXIST) {
|
||||
throw m_path + ": " + strerror(errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
} sources;
|
||||
|
||||
// redirect logging into that directory, including stderr,
|
||||
// after truncating it
|
||||
m_logfile = m_path + "/client.log";
|
||||
ofstream out;
|
||||
out.exceptions(ios_base::badbit|ios_base::failbit|ios_base::eofbit);
|
||||
out.open(m_logfile.c_str());
|
||||
out.close();
|
||||
setLogFile(m_logfile.c_str(), true);
|
||||
LOG.setLevel(LOG_LEVEL_DEBUG);
|
||||
}
|
||||
|
||||
// return log directory, empty if not enabled
|
||||
const string &getLogdir() {
|
||||
return m_path;
|
||||
}
|
||||
|
||||
// return log file, empty if not enabled
|
||||
const string &getLogfile() {
|
||||
return m_logfile;
|
||||
}
|
||||
|
||||
// remove oldest backup dirs if exceeding limit
|
||||
void expire() {
|
||||
if (m_logdir.size() && m_maxlogdirs > 0 ) {
|
||||
DIR *dir = opendir(m_logdir.c_str());
|
||||
if (!dir) {
|
||||
throw m_logdir + ": " + strerror(errno);
|
||||
}
|
||||
vector<string> entries;
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strlen(entry->d_name) >= m_prefix.size() &&
|
||||
!m_prefix.compare(0, m_prefix.size(), entry->d_name, m_prefix.size())) {
|
||||
entries.push_back(entry->d_name);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
sort(entries.begin(), entries.end());
|
||||
|
||||
int deleted = 0;
|
||||
for (vector<string>::iterator it = entries.begin();
|
||||
it != entries.end() && entries.size() - deleted > m_maxlogdirs;
|
||||
++it, ++deleted) {
|
||||
string path = m_logdir + "/" + *it;
|
||||
string msg = "removing " + path;
|
||||
LOG.info(msg.c_str());
|
||||
rmBackupDir(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove redirection of stderr and (optionally) also of logging
|
||||
void restore(bool all) {
|
||||
if (all) {
|
||||
setLogFile("-", false);
|
||||
LOG.setLevel(LOG_LEVEL_INFO);
|
||||
} else {
|
||||
setLogFile(m_logfile.c_str(), false);
|
||||
}
|
||||
}
|
||||
|
||||
~LogDir() {
|
||||
restore(true);
|
||||
}
|
||||
};
|
||||
|
||||
// this class owns the sync sources and (together with
|
||||
// a logdir) handles writing of per-sync files as well
|
||||
// as the final report (
|
||||
class SourceList : public list<EvolutionSyncSource *> {
|
||||
LogDir m_logdir; /**< our logging directory */
|
||||
bool m_doLogging; /**< true iff additional files are to be written during sync */
|
||||
bool m_reportTodo; /**< true if syncDone() shall print a final report */
|
||||
|
||||
string databaseName(EvolutionSyncSource &source, const string suffix) {
|
||||
return m_logdir.getLogdir() + "/" +
|
||||
source.getName() + "." + suffix + "." +
|
||||
source.fileSuffix();
|
||||
}
|
||||
|
||||
void dumpDatabases(const string &suffix) {
|
||||
ofstream out;
|
||||
out.exceptions(ios_base::badbit|ios_base::failbit|ios_base::eofbit);
|
||||
|
||||
for( iterator it = begin();
|
||||
it != end();
|
||||
++it ) {
|
||||
string file = databaseName(**it, suffix);
|
||||
out.open(file.c_str());
|
||||
(*it)->exportData(out);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
SourceList(const string &server, bool doLogging) :
|
||||
m_logdir(server),
|
||||
m_doLogging(doLogging),
|
||||
m_reportTodo(false) {
|
||||
}
|
||||
|
||||
// call as soon as logdir settings are known
|
||||
void setLogdir(const char *logDirPath, int maxlogdirs) {
|
||||
if (m_doLogging) {
|
||||
m_logdir.setLogdir(logDirPath, maxlogdirs);
|
||||
}
|
||||
}
|
||||
|
||||
// call when all sync sources are ready to dump
|
||||
// pre-sync databases
|
||||
void syncPrepare() {
|
||||
if (m_doLogging) {
|
||||
m_reportTodo = true;
|
||||
|
||||
// dump initial databases
|
||||
dumpDatabases("before");
|
||||
}
|
||||
}
|
||||
|
||||
// call at the end of a sync with success == true
|
||||
// if all went well to print report
|
||||
void syncDone(bool success) {
|
||||
if (m_doLogging) {
|
||||
// ensure that stderr is seen again
|
||||
m_logdir.restore(false);
|
||||
|
||||
if (m_reportTodo) {
|
||||
// haven't looked at result of sync yet;
|
||||
// don't do it again
|
||||
m_reportTodo = false;
|
||||
|
||||
// dump datatbase after sync
|
||||
dumpDatabases("after");
|
||||
|
||||
// scan for error messages
|
||||
ifstream in;
|
||||
in.open(m_logdir.getLogfile().c_str());
|
||||
while (in.good()) {
|
||||
string line;
|
||||
getline(in, line);
|
||||
if (line.find("[ERROR]") != line.npos) {
|
||||
success = false;
|
||||
cout << line << "\n";
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
cout << flush;
|
||||
|
||||
cout << "\n";
|
||||
if (success) {
|
||||
cout << "Synchronization successful.\n";
|
||||
} else {
|
||||
cout << "Synchronization failed, see "
|
||||
<< m_logdir.getLogdir()
|
||||
<< " for details.\n";
|
||||
}
|
||||
|
||||
// compare databases
|
||||
cout << "\nModifications:\n";
|
||||
for( iterator it = begin();
|
||||
it != end();
|
||||
++it ) {
|
||||
cout << "*** " << (*it)->getName() << " ***\n" << flush;
|
||||
|
||||
string before = databaseName(**it, "before");
|
||||
string after = databaseName(**it, "after");
|
||||
string cmd = string("normalize_vcard '" ) +
|
||||
before + "' '" + after +
|
||||
"' && echo 'no changes'";
|
||||
system(cmd.c_str());
|
||||
}
|
||||
cout << "\n";
|
||||
|
||||
if (success) {
|
||||
m_logdir.expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~SourceList() {
|
||||
// if we get here without a previous report,
|
||||
// something went wrong
|
||||
syncDone(false);
|
||||
|
||||
// free sync sources
|
||||
for( iterator it = begin();
|
||||
it != end();
|
||||
++it ) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void EvolutionSyncClient::sync(SyncMode syncMode, bool doLogging)
|
||||
{
|
||||
SourceList sources(m_server, doLogging);
|
||||
|
||||
DMTree config(m_configPath.c_str());
|
||||
|
||||
// find server URL (part of change id)
|
||||
|
@ -58,6 +370,10 @@ void EvolutionSyncClient::sync( SyncMode syncMode )
|
|||
auto_ptr<ManagementNode> serverNode(config.getManagementNode(serverPath.c_str()));
|
||||
string url = EvolutionSyncSource::getPropertyValue(*serverNode, "syncURL");
|
||||
|
||||
// redirect logging as soon as possible
|
||||
sources.setLogdir(serverNode->getPropertyValue("logdir"),
|
||||
atoi(serverNode->getPropertyValue("maxlogdirs")));
|
||||
|
||||
// find sources
|
||||
string sourcesPath = m_configPath + "/spds/sources";
|
||||
auto_ptr<ManagementNode> sourcesNode(config.getManagementNode(sourcesPath.c_str()));
|
||||
|
@ -103,10 +419,12 @@ void EvolutionSyncClient::sync( SyncMode syncMode )
|
|||
}
|
||||
|
||||
if (!sources.size()) {
|
||||
LOG.info( "no sources configured, done" );
|
||||
return;
|
||||
throw string("no sources configured");
|
||||
}
|
||||
|
||||
// ready to go: dump initial databases and prepare for final report
|
||||
sources.syncPrepare();
|
||||
|
||||
// build array as sync wants it, then sync
|
||||
// (no exceptions allowed here)
|
||||
SyncSource **sourceArray = new SyncSource *[sources.size() + 1];
|
||||
|
@ -134,4 +452,7 @@ void EvolutionSyncClient::sync( SyncMode syncMode )
|
|||
}
|
||||
throw res;
|
||||
}
|
||||
|
||||
// all went well: print final report before cleaning up
|
||||
sources.syncDone(true);
|
||||
}
|
||||
|
|
|
@ -45,10 +45,13 @@ class EvolutionSyncClient {
|
|||
~EvolutionSyncClient();
|
||||
|
||||
/**
|
||||
* executes the sync, throws an exception in case of failure
|
||||
* Executes the sync, throws an exception in case of failure.
|
||||
* Handles automatic backups and report generation.
|
||||
*
|
||||
* @param syncMode setting this overrides the sync mode from the config
|
||||
* @param doLogging write additional log and datatbase files about the sync
|
||||
*/
|
||||
void sync(SyncMode syncMode = SYNC_NONE);
|
||||
void sync(SyncMode syncMode = SYNC_NONE, bool doLogging = false);
|
||||
};
|
||||
|
||||
#endif // INCL_EVOLUTIONSYNCCLIENT
|
||||
|
|
|
@ -122,7 +122,11 @@ class EvolutionSyncSource : public SyncSource
|
|||
* Dump all data from source unmodified into the given stream.
|
||||
*/
|
||||
virtual void exportData(ostream &out) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* file suffix for database files
|
||||
*/
|
||||
virtual string fileSuffix() = 0;
|
||||
|
||||
/**
|
||||
* resets the lists of all/new/updated/deleted items
|
||||
|
|
|
@ -7,6 +7,9 @@ bin_PROGRAMS = syncevolution
|
|||
bin_SCRIPTS = normalize_vcard
|
||||
EXTRA_DIST = normalize_vcard.pl
|
||||
|
||||
DISTCLEANFILES = normalize_vcard
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
normalize_vcard : normalize_vcard.pl
|
||||
cp $< $@
|
||||
chmod u+x $@
|
||||
|
@ -51,7 +54,6 @@ test_LDADD = $(CORE_LDADD)
|
|||
SYNC4JSRC = @SYNC4JSRC@
|
||||
SYNC4J_SUBDIR = @SYNC4J_SUBDIR@
|
||||
BUILT_SOURCES = $(SYNC4J_SUBDIR)/all
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
clean distclean mostlyclean distdir maintainer-clean : % : $(SYNC4J_SUBDIR)/%
|
||||
clean : testclean
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#include <libgen.h>
|
||||
|
||||
#include "EvolutionContactSource.h"
|
||||
#include "EvolutionSyncClient.h"
|
||||
|
||||
|
@ -44,22 +46,36 @@ int main( int argc, char **argv )
|
|||
{
|
||||
setLogFile("-");
|
||||
LOG.reset();
|
||||
LOG.setLevel(LOG_LEVEL_DEBUG);
|
||||
LOG.setLevel(LOG_LEVEL_INFO);
|
||||
resetError();
|
||||
|
||||
// Expand PATH to cover the directory we were started from?
|
||||
// This might be needed to find normalize_vcard.
|
||||
char *exe = strdup(argv[0]);
|
||||
if (strchr(exe, '/') ) {
|
||||
char *dir = dirname(exe);
|
||||
string path;
|
||||
char *oldpath = getenv("PATH");
|
||||
if (oldpath) {
|
||||
path += oldpath;
|
||||
path += ":";
|
||||
}
|
||||
path += dir;
|
||||
setenv("PATH", path.c_str(), 1);
|
||||
}
|
||||
free(exe);
|
||||
|
||||
try {
|
||||
if ( argc != 2 ) {
|
||||
EvolutionContactSource contactSource( string( "list" ) );
|
||||
|
||||
listSources( contactSource, "address books" );
|
||||
|
||||
fprintf( stderr, "usage: %s <server>\n", argv[0] );
|
||||
fprintf( stderr, "\nusage: %s <server>\n", argv[0] );
|
||||
} else {
|
||||
EvolutionSyncClient client(argv[1]);
|
||||
client.sync();
|
||||
client.sync(SYNC_NONE, true);
|
||||
}
|
||||
|
||||
LOG.info( "synchronization successful" );
|
||||
return 0;
|
||||
} catch ( int sync4jerror ) {
|
||||
LOG.error( lastErrorMsg );
|
||||
|
@ -70,10 +86,11 @@ int main( int argc, char **argv )
|
|||
LOG.error( errmsg );
|
||||
} catch ( const string error ) {
|
||||
LOG.error( error.c_str() );
|
||||
} catch ( std::ios_base::failure error ) {
|
||||
LOG.error( error.what() );
|
||||
} catch (...) {
|
||||
LOG.error( "unknown error" );
|
||||
}
|
||||
|
||||
LOG.error( "synchronization failed" );
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue