2005-11-26 22:16:03 +01:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
#include <client/DMTClientConfig.h>
|
2006-03-19 22:37:30 +01:00
|
|
|
#include <posix/base/posixlog.h>
|
2005-11-26 22:16:03 +01:00
|
|
|
|
|
|
|
#include <list>
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
2006-03-19 22:37:30 +01:00
|
|
|
#include <sstream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <iostream>
|
2006-05-26 14:49:19 +02:00
|
|
|
#include <stdexcept>
|
2005-11-26 22:16:03 +01:00
|
|
|
using namespace std;
|
|
|
|
|
2006-03-19 22:37:30 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2006-09-29 01:02:43 +02:00
|
|
|
EvolutionSyncClient::EvolutionSyncClient(const string &server,
|
2006-08-06 09:56:41 +02:00
|
|
|
bool doLogging, const set<string> &sources) :
|
2005-11-26 22:16:03 +01:00
|
|
|
m_server(server),
|
2006-04-09 13:48:11 +02:00
|
|
|
m_sources(sources),
|
2006-08-06 09:56:41 +02:00
|
|
|
m_doLogging(doLogging),
|
2006-08-14 22:52:34 +02:00
|
|
|
m_configPath(string("evolution/") + server)
|
2005-11-26 22:16:03 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
EvolutionSyncClient::~EvolutionSyncClient()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-03-19 22:37:30 +01:00
|
|
|
/// remove all files in the given directory and the directory itself
|
|
|
|
static void rmBackupDir(const string &dirname)
|
2005-11-26 22:16:03 +01:00
|
|
|
{
|
2006-03-19 22:37:30 +01:00
|
|
|
DIR *dir = opendir(dirname.c_str());
|
|
|
|
if (!dir) {
|
2006-05-26 14:49:19 +02:00
|
|
|
throw runtime_error(dirname + ": " + strerror(errno));
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
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
|
|
|
|
) {
|
2006-05-26 14:49:19 +02:00
|
|
|
throw runtime_error(path + ": " + strerror(errno));
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rmdir(dirname.c_str())) {
|
2006-05-26 14:49:19 +02:00
|
|
|
throw runtime_error(dirname + ": " + strerror(errno));
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 */
|
2006-04-06 19:02:43 +02:00
|
|
|
LogLevel m_oldLogLevel; /**< logging level to restore */
|
|
|
|
|
2006-03-19 22:37:30 +01:00
|
|
|
|
|
|
|
public:
|
2006-04-06 19:02:43 +02:00
|
|
|
LogDir(const string &server) : m_server(server),
|
|
|
|
m_oldLogLevel(LOG.getLevel())
|
|
|
|
{}
|
2006-03-19 22:37:30 +01:00
|
|
|
|
|
|
|
// 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 << "-"
|
2006-06-19 18:23:07 +02:00
|
|
|
<< setw(2) << tm->tm_mday << "-"
|
|
|
|
<< setw(2) << tm->tm_hour << "-"
|
|
|
|
<< setw(2) << tm->tm_min;
|
2006-03-19 22:37:30 +01:00
|
|
|
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) {
|
2006-05-26 14:49:19 +02:00
|
|
|
throw runtime_error(m_path + ": " + strerror(errno));
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
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) {
|
2006-05-26 14:49:19 +02:00
|
|
|
throw runtime_error(m_path + ": " + strerror(errno));
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2006-05-26 14:49:19 +02:00
|
|
|
throw runtime_error(m_logdir + ": " + strerror(errno));
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
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());
|
|
|
|
|
2006-06-11 22:07:26 +02:00
|
|
|
unsigned int deleted = 0;
|
2006-03-19 22:37:30 +01:00
|
|
|
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);
|
2006-04-06 19:02:43 +02:00
|
|
|
LOG.setLevel(m_oldLogLevel);
|
2006-03-19 22:37:30 +01:00
|
|
|
} 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 */
|
2006-09-07 21:47:29 +02:00
|
|
|
arrayptr<SyncSource *> m_sourceArray; /** owns the array that is expected by SyncClient::sync() */
|
2006-03-19 22:37:30 +01:00
|
|
|
|
|
|
|
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);
|
2006-04-06 19:02:43 +02:00
|
|
|
} else {
|
|
|
|
// at least increase log level
|
|
|
|
LOG.setLevel(LOG_LEVEL_DEBUG);
|
|
|
|
}
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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";
|
2006-04-09 13:48:11 +02:00
|
|
|
} else if (line.find("[INFO]") != line.npos) {
|
|
|
|
cout << line << "\n";
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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");
|
2006-05-24 21:38:45 +02:00
|
|
|
string cmd = string("synccompare '" ) +
|
2006-03-19 22:37:30 +01:00
|
|
|
before + "' '" + after +
|
|
|
|
"' && echo 'no changes'";
|
|
|
|
system(cmd.c_str());
|
|
|
|
}
|
|
|
|
cout << "\n";
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
m_logdir.expire();
|
|
|
|
}
|
2005-11-26 22:16:03 +01:00
|
|
|
}
|
|
|
|
}
|
2006-03-19 22:37:30 +01:00
|
|
|
}
|
2006-09-07 21:47:29 +02:00
|
|
|
|
|
|
|
/** returns current sources as array as expected by SyncClient::sync(), memory owned by this class */
|
|
|
|
SyncSource **getSourceArray() {
|
|
|
|
m_sourceArray = new SyncSource *[size() + 1];
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
for (iterator it = begin();
|
|
|
|
it != end();
|
|
|
|
++it) {
|
|
|
|
((SyncSource **)m_sourceArray)[index] = *it;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
((SyncSource **)m_sourceArray)[index] = 0;
|
|
|
|
return m_sourceArray;
|
|
|
|
}
|
|
|
|
|
2006-03-19 22:37:30 +01:00
|
|
|
~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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-08-14 22:52:34 +02:00
|
|
|
void unref(SourceList *sourceList)
|
|
|
|
{
|
|
|
|
delete sourceList;
|
|
|
|
}
|
|
|
|
|
2006-08-06 09:56:41 +02:00
|
|
|
int EvolutionSyncClient::sync()
|
2006-03-19 22:37:30 +01:00
|
|
|
{
|
2006-09-07 21:47:29 +02:00
|
|
|
class EvolutionClientConfig : public DMTClientConfig {
|
|
|
|
public:
|
|
|
|
EvolutionClientConfig(const char *root) :
|
|
|
|
DMTClientConfig(root) {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
/*
|
|
|
|
* tweak the base class in two ways:
|
|
|
|
* - continue to use the "syncml" node for all non-source properties, as in previous versions
|
|
|
|
* - do not save properties which cannot be configured
|
|
|
|
*/
|
|
|
|
virtual int readAuthConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& authNode) {
|
|
|
|
return DMTClientConfig::readAuthConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual void saveAuthConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& authNode) {
|
|
|
|
DMTClientConfig::saveAuthConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual int readConnConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& connNode) {
|
|
|
|
return DMTClientConfig::readConnConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual void saveConnConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& connNode) {
|
|
|
|
DMTClientConfig::saveConnConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual int readExtAccessConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& extNode) {
|
|
|
|
return DMTClientConfig::readExtAccessConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual void saveExtAccessConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& extNode) {
|
|
|
|
DMTClientConfig::saveExtAccessConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual int readDevInfoConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& devInfoNode) {
|
2006-09-08 21:57:08 +02:00
|
|
|
int res = DMTClientConfig::readDevInfoConfig(syncMLNode, syncMLNode);
|
|
|
|
|
|
|
|
// always read device ID from the traditional property "deviceId"
|
|
|
|
char* tmp;
|
|
|
|
tmp = syncMLNode.getPropertyValue("deviceId");
|
|
|
|
deviceConfig.setDevID(tmp);
|
|
|
|
delete [] tmp;
|
|
|
|
|
|
|
|
return res;
|
2006-09-07 21:47:29 +02:00
|
|
|
}
|
|
|
|
virtual void saveDevInfoConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& devInfoNode) {
|
|
|
|
// these properties are always set by the code, don't save them
|
|
|
|
}
|
|
|
|
virtual int readDevDetailConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& devDetailNode) {
|
|
|
|
return DMTClientConfig::readDevDetailConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual void saveDevDetailConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& devDetailNode) {
|
|
|
|
// these properties are always set by the code, don't save them
|
|
|
|
}
|
|
|
|
virtual int readExtDevConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& extNode) {
|
|
|
|
return DMTClientConfig::readExtDevConfig(syncMLNode, syncMLNode);
|
|
|
|
}
|
|
|
|
virtual void saveExtDevConfig(ManagementNode& syncMLNode,
|
|
|
|
ManagementNode& extNode) {
|
|
|
|
// these properties are always set by the code, don't save them
|
2006-08-06 09:56:41 +02:00
|
|
|
}
|
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
virtual void saveSourceConfig(int i,
|
|
|
|
ManagementNode& sourcesNode,
|
|
|
|
ManagementNode& sourceNode) {
|
|
|
|
// no, don't overwrite config, in particular not the "type"
|
2006-08-06 09:56:41 +02:00
|
|
|
}
|
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
} config(m_configPath.c_str());
|
|
|
|
|
|
|
|
if (!config.read() || !config.open()) {
|
|
|
|
throw runtime_error("reading configuration failed");
|
|
|
|
}
|
2006-08-06 09:56:41 +02:00
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
// remember for use by sync sources
|
|
|
|
string url = config.getAccessConfig().getSyncURL() ? config.getAccessConfig().getSyncURL() : "";
|
2006-08-14 22:52:34 +02:00
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
if (!url.size()) {
|
|
|
|
LOG.error("no syncURL configured - perhaps the server name \"%s\" is wrong?",
|
|
|
|
m_server.c_str());
|
|
|
|
throw runtime_error("cannot proceed without configuration");
|
2006-08-06 09:56:41 +02:00
|
|
|
}
|
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
// redirect logging as soon as possible
|
|
|
|
SourceList sourceList(m_server, m_doLogging);
|
|
|
|
sourceList.setLogdir(config.getSyncMLNode()->getPropertyValue("logdir"),
|
|
|
|
atoi(config.getSyncMLNode()->getPropertyValue("maxlogdirs")));
|
2006-08-06 09:56:41 +02:00
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
SyncSourceConfig *sourceconfigs = config.getSyncSourceConfigs();
|
|
|
|
for (int index = 0; index < config.getNumSources(); index++) {
|
|
|
|
ManagementNode &node(*config.getSyncSourceNode(index));
|
|
|
|
SyncSourceConfig &sc(sourceconfigs[index]);
|
2006-08-06 09:56:41 +02:00
|
|
|
|
2005-11-26 22:16:03 +01:00
|
|
|
// is the source enabled?
|
2006-09-07 21:47:29 +02:00
|
|
|
string sync = sc.getSync() ? sc.getSync() : "";
|
2006-04-09 13:48:11 +02:00
|
|
|
bool enabled = sync != "none";
|
|
|
|
SyncMode overrideMode = SYNC_NONE;
|
|
|
|
|
|
|
|
// override state?
|
|
|
|
if (m_sources.size()) {
|
2006-09-07 21:47:29 +02:00
|
|
|
if (m_sources.find(sc.getName()) != m_sources.end()) {
|
2006-04-09 13:48:11 +02:00
|
|
|
if (!enabled) {
|
|
|
|
overrideMode = SYNC_TWO_WAY;
|
|
|
|
enabled = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
enabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (enabled) {
|
2005-11-26 22:16:03 +01:00
|
|
|
// create it
|
2006-09-07 21:47:29 +02:00
|
|
|
string type = sc.getType() ? sc.getType() : "";
|
2005-11-26 22:16:03 +01:00
|
|
|
EvolutionSyncSource *syncSource =
|
|
|
|
EvolutionSyncSource::createSource(
|
2006-09-07 21:47:29 +02:00
|
|
|
sc.getName(),
|
2006-09-29 01:02:43 +02:00
|
|
|
&sc,
|
2006-09-07 21:47:29 +02:00
|
|
|
string("sync4jevolution:") + url + "/" + sc.getName(),
|
2006-08-06 09:56:41 +02:00
|
|
|
EvolutionSyncSource::getPropertyValue(node, "evolutionsource"),
|
2005-11-26 22:16:03 +01:00
|
|
|
type
|
|
|
|
);
|
|
|
|
if (!syncSource) {
|
2006-09-07 21:47:29 +02:00
|
|
|
throw runtime_error(string(sc.getName()) + ": type " +
|
2006-05-26 14:49:19 +02:00
|
|
|
( type.size() ? string("not configured") :
|
|
|
|
string("'") + type + "' empty or unknown" ));
|
2005-11-26 22:16:03 +01:00
|
|
|
}
|
2006-09-07 21:47:29 +02:00
|
|
|
sourceList.push_back(syncSource);
|
|
|
|
|
2006-10-04 21:39:00 +02:00
|
|
|
// Update the backend configuration. The EvolutionClientConfig
|
2006-09-08 21:57:08 +02:00
|
|
|
// above prevents that these modifications overwrite the user settings.
|
2006-09-07 21:47:29 +02:00
|
|
|
sc.setType(syncSource->getMimeType());
|
|
|
|
sc.setVersion(syncSource->getMimeVersion());
|
2006-09-16 11:00:50 +02:00
|
|
|
sc.setSupportedTypes(syncSource->getSupportedTypes());
|
2006-04-09 13:48:11 +02:00
|
|
|
|
2006-09-29 01:02:43 +02:00
|
|
|
if (overrideMode != SYNC_NONE) {
|
2006-04-09 13:48:11 +02:00
|
|
|
// disabled source selected via source name
|
2006-08-06 09:56:41 +02:00
|
|
|
syncSource->setPreferredSyncMode(overrideMode);
|
2006-04-06 19:02:43 +02:00
|
|
|
}
|
2006-08-17 22:26:08 +02:00
|
|
|
const string user(EvolutionSyncSource::getPropertyValue(node, "evolutionuser")),
|
|
|
|
passwd(EvolutionSyncSource::getPropertyValue(node, "evolutionpassword"));
|
|
|
|
syncSource->setAuthentication(user, passwd);
|
2006-04-09 13:48:11 +02:00
|
|
|
|
2005-11-26 22:16:03 +01:00
|
|
|
// also open it; failing now is still safe
|
2006-09-07 21:47:29 +02:00
|
|
|
syncSource->open();
|
2006-05-25 19:32:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
// reconfigure with our fixed properties
|
|
|
|
DeviceConfig &dc(config.getDeviceConfig());
|
2006-10-29 16:22:37 +01:00
|
|
|
dc.setVerDTD("1.1");
|
2006-09-07 21:47:29 +02:00
|
|
|
dc.setMod("SyncEvolution");
|
|
|
|
dc.setSwv(VERSION);
|
|
|
|
dc.setMan("Patrick Ohly");
|
|
|
|
dc.setDevType("workstation");
|
|
|
|
dc.setUtc(1);
|
|
|
|
dc.setOem("Open Source");
|
|
|
|
|
2006-09-29 01:02:43 +02:00
|
|
|
// give derived class also a chance to update the configs
|
|
|
|
prepare(config, sourceList.getSourceArray());
|
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
// ready to go: dump initial databases and prepare for final report
|
|
|
|
sourceList.syncPrepare();
|
|
|
|
|
|
|
|
// do it
|
|
|
|
int res = SyncClient::sync(config, sourceList.getSourceArray());
|
|
|
|
|
|
|
|
if (res) {
|
|
|
|
if (lastErrorCode && lastErrorMsg[0]) {
|
|
|
|
throw runtime_error(lastErrorMsg);
|
|
|
|
}
|
|
|
|
// no error code/description?!
|
|
|
|
throw runtime_error("sync failed without an error description, check log");
|
2005-11-26 22:16:03 +01:00
|
|
|
}
|
2006-03-19 22:37:30 +01:00
|
|
|
|
2006-09-07 21:47:29 +02:00
|
|
|
// store modified properties
|
|
|
|
config.save();
|
|
|
|
|
|
|
|
// all went well: print final report before cleaning up
|
|
|
|
sourceList.syncDone(true);
|
2005-11-26 22:16:03 +01:00
|
|
|
}
|