2005-11-05 23:04:33 +01:00
|
|
|
/*
|
2008-08-26 19:45:28 +02:00
|
|
|
* Copyright (C) 2005-2008 Patrick Ohly
|
2005-11-05 23:04:33 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <memory>
|
2006-09-09 10:36:04 +02:00
|
|
|
#include <map>
|
|
|
|
#include <sstream>
|
2007-11-08 23:18:59 +01:00
|
|
|
#include <list>
|
2005-11-05 23:04:33 +01:00
|
|
|
using namespace std;
|
|
|
|
|
2006-07-23 12:27:21 +02:00
|
|
|
#include "config.h"
|
2008-03-10 23:45:36 +01:00
|
|
|
#include "EvolutionSyncSource.h"
|
2006-07-23 12:27:21 +02:00
|
|
|
|
|
|
|
#ifdef ENABLE_EBOOK
|
|
|
|
|
2007-10-11 23:02:49 +02:00
|
|
|
#include "EvolutionSyncClient.h"
|
2005-11-05 23:04:33 +01:00
|
|
|
#include "EvolutionContactSource.h"
|
2008-03-25 22:54:05 +01:00
|
|
|
#include "SyncEvolutionUtil.h"
|
2005-11-05 23:04:33 +01:00
|
|
|
|
2005-12-03 15:35:11 +01:00
|
|
|
#include <common/base/Log.h>
|
2006-06-11 15:09:29 +02:00
|
|
|
#include "vocl/VConverter.h"
|
|
|
|
using namespace vocl;
|
2005-12-03 15:35:11 +01:00
|
|
|
|
2008-03-29 16:41:11 +01:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2008-07-11 22:25:02 +02:00
|
|
|
#include <boost/foreach.hpp>
|
2008-03-29 16:41:11 +01:00
|
|
|
|
2008-03-18 14:36:59 +01:00
|
|
|
class unrefEBookChanges {
|
|
|
|
public:
|
|
|
|
/** free list of EBookChange instances */
|
|
|
|
static void unref(GList *pointer) {
|
|
|
|
if (pointer) {
|
|
|
|
GList *next = pointer;
|
|
|
|
do {
|
|
|
|
EBookChange *ebc = (EBookChange *)next->data;
|
|
|
|
g_object_unref(ebc->contact);
|
|
|
|
g_free(next->data);
|
|
|
|
next = next->next;
|
|
|
|
} while (next);
|
|
|
|
g_list_free(pointer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2006-03-12 23:30:35 +01:00
|
|
|
const EvolutionContactSource::extensions EvolutionContactSource::m_vcardExtensions;
|
2006-03-18 15:18:14 +01:00
|
|
|
const EvolutionContactSource::unique EvolutionContactSource::m_uniqueProperties;
|
2006-03-12 23:30:35 +01:00
|
|
|
|
2008-03-06 23:23:13 +01:00
|
|
|
EvolutionContactSource::EvolutionContactSource(const EvolutionSyncSourceParams ¶ms,
|
|
|
|
EVCardFormat vcardFormat) :
|
|
|
|
EvolutionSyncSource(params),
|
|
|
|
m_vcardFormat(vcardFormat)
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-01-08 22:49:03 +01:00
|
|
|
EvolutionContactSource::EvolutionContactSource( const EvolutionContactSource &other ) :
|
|
|
|
EvolutionSyncSource( other ),
|
|
|
|
m_vcardFormat( other.m_vcardFormat )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-07-10 21:17:42 +02:00
|
|
|
EvolutionSyncSource::Databases EvolutionContactSource::getDatabases()
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
|
|
|
ESourceList *sources = NULL;
|
|
|
|
|
|
|
|
if (!e_book_get_addressbooks(&sources, NULL)) {
|
2007-10-11 23:02:49 +02:00
|
|
|
EvolutionSyncClient::throwError("unable to access address books");
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2008-07-10 21:17:42 +02:00
|
|
|
Databases result;
|
2008-03-30 21:08:19 +02:00
|
|
|
bool first = true;
|
2005-11-05 23:04:33 +01:00
|
|
|
for (GSList *g = e_source_list_peek_groups (sources); g; g = g->next) {
|
|
|
|
ESourceGroup *group = E_SOURCE_GROUP (g->data);
|
|
|
|
for (GSList *s = e_source_group_peek_sources (group); s; s = s->next) {
|
|
|
|
ESource *source = E_SOURCE (s->data);
|
2008-07-03 21:59:03 +02:00
|
|
|
eptr<char> uri(e_source_get_uri(source));
|
2008-07-10 21:17:42 +02:00
|
|
|
result.push_back(Database(e_source_peek_name(source),
|
2008-07-03 21:59:03 +02:00
|
|
|
uri ? uri.get() : "",
|
|
|
|
first));
|
2008-03-30 21:08:19 +02:00
|
|
|
first = false;
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
}
|
2006-11-01 13:59:41 +01:00
|
|
|
|
|
|
|
// No results? Try system address book (workaround for embedded Evolution Dataserver).
|
|
|
|
if (!result.size()) {
|
|
|
|
eptr<EBook, GObject> book;
|
2007-03-25 22:17:44 +02:00
|
|
|
GError *gerror = NULL;
|
2006-11-01 13:59:41 +01:00
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = "<<system>>";
|
|
|
|
book = e_book_new_system_addressbook (&gerror);
|
|
|
|
g_clear_error(&gerror);
|
|
|
|
if (!book) {
|
|
|
|
name = "<<default>>";
|
|
|
|
book = e_book_new_default_addressbook (&gerror);
|
|
|
|
}
|
|
|
|
g_clear_error(&gerror);
|
|
|
|
|
|
|
|
if (book) {
|
|
|
|
const char *uri = e_book_get_uri (book);
|
2008-07-10 21:17:42 +02:00
|
|
|
result.push_back(Database(name, uri, true));
|
2006-11-01 13:59:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-05 23:04:33 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EvolutionContactSource::open()
|
|
|
|
{
|
|
|
|
ESourceList *sources;
|
|
|
|
if (!e_book_get_addressbooks(&sources, NULL)) {
|
2007-10-11 23:02:49 +02:00
|
|
|
throwError("unable to access address books");
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2006-11-01 13:59:41 +01:00
|
|
|
GError *gerror = NULL;
|
2008-03-06 23:23:13 +01:00
|
|
|
string id = getDatabaseID();
|
|
|
|
ESource *source = findSource(sources, id);
|
2007-04-01 15:02:56 +02:00
|
|
|
bool onlyIfExists = true;
|
2005-11-05 23:04:33 +01:00
|
|
|
if (!source) {
|
2007-04-01 15:02:56 +02:00
|
|
|
// might have been special "<<system>>" or "<<default>>", try that and
|
|
|
|
// creating address book from file:// URI before giving up
|
2008-03-30 21:08:19 +02:00
|
|
|
if (id.empty() || id == "<<system>>") {
|
2006-11-01 13:59:41 +01:00
|
|
|
m_addressbook.set( e_book_new_system_addressbook (&gerror), "system address book" );
|
2008-03-30 21:08:19 +02:00
|
|
|
} else if (id.empty() || id == "<<default>>") {
|
2006-11-01 13:59:41 +01:00
|
|
|
m_addressbook.set( e_book_new_default_addressbook (&gerror), "default address book" );
|
2008-03-30 21:08:19 +02:00
|
|
|
} else if (boost::starts_with(id, "file://")) {
|
2008-03-06 23:23:13 +01:00
|
|
|
m_addressbook.set(e_book_new_from_uri(id.c_str(), &gerror), "creating address book");
|
2006-11-01 13:59:41 +01:00
|
|
|
} else {
|
2008-03-06 23:23:13 +01:00
|
|
|
throwError(string(getName()) + ": no such address book: '" + id + "'");
|
2006-11-01 13:59:41 +01:00
|
|
|
}
|
2007-04-01 15:02:56 +02:00
|
|
|
onlyIfExists = false;
|
2006-11-01 13:59:41 +01:00
|
|
|
} else {
|
|
|
|
m_addressbook.set( e_book_new( source, &gerror ), "address book" );
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-08-17 22:26:08 +02:00
|
|
|
|
2007-04-01 15:02:56 +02:00
|
|
|
if (!e_book_open( m_addressbook, onlyIfExists, &gerror) ) {
|
|
|
|
// opening newly created address books often fails, try again once more
|
2007-04-09 21:59:39 +02:00
|
|
|
g_clear_error(&gerror);
|
2007-04-01 15:02:56 +02:00
|
|
|
sleep(5);
|
|
|
|
if (!e_book_open( m_addressbook, onlyIfExists, &gerror) ) {
|
|
|
|
throwError( "opening address book", gerror );
|
|
|
|
}
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-08-17 22:26:08 +02:00
|
|
|
|
|
|
|
// users are not expected to configure an authentication method,
|
|
|
|
// so pick one automatically if the user indicated that he wants authentication
|
|
|
|
// by setting user or password
|
2008-04-03 22:01:56 +02:00
|
|
|
const char *user = getUser(),
|
|
|
|
*passwd = getPassword();
|
2008-03-06 23:23:13 +01:00
|
|
|
if (user && user[0] || passwd && passwd[0]) {
|
2006-08-17 22:26:08 +02:00
|
|
|
GList *authmethod;
|
|
|
|
if (!e_book_get_supported_auth_methods(m_addressbook, &authmethod, &gerror)) {
|
|
|
|
throwError("getting authentication methods", gerror );
|
|
|
|
}
|
|
|
|
while (authmethod) {
|
|
|
|
const char *method = (const char *)authmethod->data;
|
|
|
|
LOG.debug("%s: trying authentication method \"%s\", user %s, password %s",
|
|
|
|
getName(), method,
|
2008-03-06 23:23:13 +01:00
|
|
|
user && user[0] ? "configured" : "not configured",
|
|
|
|
passwd && passwd[0] ? "configured" : "not configured");
|
2006-08-17 22:26:08 +02:00
|
|
|
if (e_book_authenticate_user(m_addressbook,
|
2008-03-06 23:23:13 +01:00
|
|
|
user ? user : "",
|
|
|
|
passwd ? passwd : "",
|
2006-08-17 22:26:08 +02:00
|
|
|
method,
|
|
|
|
&gerror)) {
|
|
|
|
LOG.debug("%s: authentication succeeded", getName());
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
LOG.error("%s: authentication failed: %s",
|
|
|
|
getName(), gerror->message);
|
|
|
|
g_clear_error(&gerror);
|
|
|
|
}
|
2008-02-24 18:59:02 +01:00
|
|
|
authmethod = authmethod->next;
|
2006-08-17 22:26:08 +02:00
|
|
|
}
|
|
|
|
}
|
2007-11-03 18:07:42 +01:00
|
|
|
|
|
|
|
g_signal_connect_after(m_addressbook,
|
|
|
|
"backend-died",
|
|
|
|
G_CALLBACK(EvolutionSyncClient::fatalError),
|
|
|
|
(void *)"Evolution Data Server has died unexpectedly, contacts no longer available.");
|
2005-11-26 22:16:03 +01:00
|
|
|
}
|
2005-11-05 23:04:33 +01:00
|
|
|
|
2006-04-09 13:48:11 +02:00
|
|
|
void EvolutionContactSource::beginSyncThrow(bool needAll,
|
|
|
|
bool needPartial,
|
|
|
|
bool deleteLocal)
|
2005-11-26 22:16:03 +01:00
|
|
|
{
|
2006-04-09 13:48:11 +02:00
|
|
|
GError *gerror = NULL;
|
2005-11-26 22:16:03 +01:00
|
|
|
|
2007-06-27 22:24:45 +02:00
|
|
|
eptr<EBookQuery> deleteItemsQuery;
|
2006-04-09 13:48:11 +02:00
|
|
|
if (deleteLocal) {
|
2007-06-27 22:24:45 +02:00
|
|
|
deleteItemsQuery.set( e_book_query_any_field_contains(""), "query" );
|
|
|
|
}
|
2008-07-21 18:53:49 +02:00
|
|
|
#ifdef ENABLE_MAEMO_OSSO_CONTACT_STATE
|
2007-06-27 22:24:45 +02:00
|
|
|
else {
|
2007-06-28 22:11:19 +02:00
|
|
|
deleteItemsQuery.set( e_book_query_vcard_field_exists("X-OSSO-CONTACT-STATE"), "query" );
|
2007-06-27 22:24:45 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (deleteItemsQuery) {
|
2006-04-09 13:48:11 +02:00
|
|
|
GList *nextItem;
|
2007-06-27 22:24:45 +02:00
|
|
|
|
|
|
|
if (!e_book_get_contacts( m_addressbook, deleteItemsQuery, &nextItem, &gerror )) {
|
|
|
|
throwError( "reading items to be deleted", gerror );
|
2005-12-11 18:13:36 +01:00
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<GList> listptr(nextItem);
|
2007-06-28 22:11:19 +02:00
|
|
|
for (;nextItem; nextItem = nextItem->next) {
|
2006-04-09 13:48:11 +02:00
|
|
|
const char *uid = (const char *)e_contact_get_const(E_CONTACT(nextItem->data),
|
2005-12-11 18:13:36 +01:00
|
|
|
E_CONTACT_UID);
|
2008-07-21 18:53:49 +02:00
|
|
|
#ifdef ENABLE_MAEMO_OSSO_CONTACT_STATE
|
2007-06-27 22:24:45 +02:00
|
|
|
if (!deleteLocal) {
|
2007-06-28 22:11:19 +02:00
|
|
|
GList *nextState = (GList *)e_contact_get(E_CONTACT(nextItem->data),
|
|
|
|
E_CONTACT_OSSO_CONTACT_STATE);
|
|
|
|
bool deleted = false;
|
|
|
|
while (nextState) {
|
2008-04-20 14:34:11 +02:00
|
|
|
LOG.debug("checking X-OSSO-CONTACT-STATE %p of uid %s",
|
|
|
|
nextState->data, uid);
|
|
|
|
if ((char *)nextState->data < (char *)1024) {
|
|
|
|
LOG.info("broken X-OSSO-CONTACT-STATE %p, please report this to the SyncEvolution developer",
|
|
|
|
nextState->data);
|
|
|
|
} else {
|
|
|
|
LOG.debug("X-OSSO-CONTACT-STATE %p = %s",
|
|
|
|
nextState->data, (char *)nextState->data);
|
|
|
|
if (nextState->data && !strcmp((char *)nextState->data, "DELETED")) {
|
|
|
|
deleted = true;
|
|
|
|
}
|
2007-06-28 22:11:19 +02:00
|
|
|
}
|
|
|
|
nextState = nextState->next;
|
|
|
|
}
|
|
|
|
if (!deleted) {
|
|
|
|
continue;
|
|
|
|
}
|
2008-04-07 19:59:17 +02:00
|
|
|
logItem(string(uid), "deleting item scheduled for removal", true);
|
2007-06-28 22:11:19 +02:00
|
|
|
if (needPartial) {
|
|
|
|
// the observation is that the deleted item is not listed again
|
|
|
|
// below; apparently only changes made by someone else are recorded
|
|
|
|
// in the list of changes ?!
|
|
|
|
m_deletedItems.addItem(uid);
|
|
|
|
}
|
2007-06-27 22:24:45 +02:00
|
|
|
}
|
2007-06-28 22:11:19 +02:00
|
|
|
#endif
|
2006-04-09 13:48:11 +02:00
|
|
|
if (!e_book_remove_contact( m_addressbook, uid, &gerror ) ) {
|
2006-09-10 10:06:17 +02:00
|
|
|
throwError( string( "deleting contact " ) + uid,
|
2006-04-09 13:48:11 +02:00
|
|
|
gerror );
|
2005-12-11 18:13:36 +01:00
|
|
|
}
|
|
|
|
}
|
2006-04-09 13:48:11 +02:00
|
|
|
}
|
2005-12-11 18:13:36 +01:00
|
|
|
|
2006-04-09 13:48:11 +02:00
|
|
|
if (needAll) {
|
2006-08-14 22:52:34 +02:00
|
|
|
eptr<EBookQuery> allItemsQuery( e_book_query_any_field_contains(""), "query" );
|
2006-04-09 13:48:11 +02:00
|
|
|
GList *nextItem;
|
|
|
|
if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) {
|
|
|
|
throwError( "reading all items", gerror );
|
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<GList> listptr(nextItem);
|
2006-04-09 13:48:11 +02:00
|
|
|
while (nextItem) {
|
|
|
|
const char *uid = (const char *)e_contact_get_const(E_CONTACT(nextItem->data),
|
2005-12-03 15:35:11 +01:00
|
|
|
E_CONTACT_UID);
|
2006-04-09 13:48:11 +02:00
|
|
|
m_allItems.addItem(uid);
|
|
|
|
nextItem = nextItem->next;
|
2005-12-11 18:13:36 +01:00
|
|
|
}
|
2006-04-09 13:48:11 +02:00
|
|
|
}
|
2005-12-10 22:10:43 +01:00
|
|
|
|
2006-04-09 13:48:11 +02:00
|
|
|
if (needPartial) {
|
|
|
|
GList *nextItem;
|
|
|
|
if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) {
|
|
|
|
throwError( "reading changes", gerror );
|
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<GList, GList, unrefEBookChanges> listptr(nextItem);
|
2006-04-09 13:48:11 +02:00
|
|
|
while (nextItem) {
|
|
|
|
EBookChange *ebc = (EBookChange *)nextItem->data;
|
2006-06-11 10:56:24 +02:00
|
|
|
|
|
|
|
if (ebc->contact) {
|
|
|
|
const char *uid = (const char *)e_contact_get_const( ebc->contact, E_CONTACT_UID );
|
|
|
|
|
|
|
|
if (uid) {
|
|
|
|
switch (ebc->change_type) {
|
|
|
|
case E_BOOK_CHANGE_CARD_ADDED:
|
|
|
|
m_newItems.addItem(uid);
|
|
|
|
break;
|
|
|
|
case E_BOOK_CHANGE_CARD_MODIFIED:
|
|
|
|
m_updatedItems.addItem(uid);
|
|
|
|
break;
|
|
|
|
case E_BOOK_CHANGE_CARD_DELETED:
|
|
|
|
m_deletedItems.addItem(uid);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-12-10 22:10:43 +01:00
|
|
|
}
|
2006-04-09 13:48:11 +02:00
|
|
|
nextItem = nextItem->next;
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
}
|
2005-11-26 22:16:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void EvolutionContactSource::endSyncThrow()
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
2005-11-26 22:16:03 +01:00
|
|
|
if (m_isModified) {
|
2005-11-05 23:04:33 +01:00
|
|
|
GError *gerror = NULL;
|
|
|
|
GList *nextItem;
|
|
|
|
// move change_id forward so that our own changes are not listed the next time
|
|
|
|
if (!e_book_get_changes( m_addressbook, (char *)m_changeId.c_str(), &nextItem, &gerror )) {
|
|
|
|
throwError( "reading changes", gerror );
|
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<GList, GList, unrefEBookChanges> listptr(nextItem);
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2005-11-26 22:16:03 +01:00
|
|
|
resetItems();
|
|
|
|
m_isModified = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EvolutionContactSource::close()
|
|
|
|
{
|
|
|
|
endSyncThrow();
|
2005-11-05 23:04:33 +01:00
|
|
|
m_addressbook = NULL;
|
|
|
|
}
|
|
|
|
|
2006-03-18 14:35:23 +01:00
|
|
|
void EvolutionContactSource::exportData(ostream &out)
|
|
|
|
{
|
2006-08-14 22:52:34 +02:00
|
|
|
eptr<EBookQuery> allItemsQuery( e_book_query_any_field_contains(""), "query" );
|
2006-03-18 14:35:23 +01:00
|
|
|
GList *nextItem;
|
|
|
|
GError *gerror = NULL;
|
|
|
|
if (!e_book_get_contacts( m_addressbook, allItemsQuery, &nextItem, &gerror )) {
|
|
|
|
throwError( "reading all items", gerror );
|
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<GList> listptr(nextItem);
|
2006-03-18 14:35:23 +01:00
|
|
|
while (nextItem) {
|
2006-08-14 22:52:34 +02:00
|
|
|
eptr<char> vcardstr(e_vcard_to_string(&E_CONTACT(nextItem->data)->parent,
|
2006-04-26 22:44:41 +02:00
|
|
|
EVC_FORMAT_VCARD_30));
|
2006-03-18 14:35:23 +01:00
|
|
|
|
2007-03-24 23:51:14 +01:00
|
|
|
if (!(const char *)vcardstr) {
|
2007-10-11 23:02:49 +02:00
|
|
|
throwError("could not convert contact into string");
|
2007-03-24 23:51:14 +01:00
|
|
|
}
|
2006-03-18 14:35:23 +01:00
|
|
|
out << (const char *)vcardstr << "\r\n\r\n";
|
|
|
|
nextItem = nextItem->next;
|
|
|
|
}
|
|
|
|
}
|
2005-11-05 23:04:33 +01:00
|
|
|
|
2008-01-13 02:41:21 +01:00
|
|
|
SyncItem *EvolutionContactSource::createItem(const string &uid)
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
2007-08-25 15:22:26 +02:00
|
|
|
logItem( uid, "extracting from EV", true );
|
2007-03-23 22:00:32 +01:00
|
|
|
|
2006-05-26 14:49:19 +02:00
|
|
|
EContact *contact;
|
|
|
|
GError *gerror = NULL;
|
|
|
|
if (! e_book_get_contact( m_addressbook,
|
|
|
|
uid.c_str(),
|
|
|
|
&contact,
|
|
|
|
&gerror ) ) {
|
2006-09-10 10:06:17 +02:00
|
|
|
throwError( string( "reading contact " ) + uid,
|
2006-05-26 14:49:19 +02:00
|
|
|
gerror );
|
|
|
|
}
|
2006-08-14 22:52:34 +02:00
|
|
|
eptr<EContact, GObject> contactptr( contact, "contact" );
|
|
|
|
eptr<char> vcardstr(e_vcard_to_string( &contactptr->parent,
|
2006-05-26 14:49:19 +02:00
|
|
|
EVC_FORMAT_VCARD_30 ) );
|
|
|
|
if (!vcardstr) {
|
2008-08-09 12:26:52 +02:00
|
|
|
throwError(string("failure extracting contact from Evolution " ) + uid);
|
2006-05-26 14:49:19 +02:00
|
|
|
}
|
2008-06-12 20:47:55 +02:00
|
|
|
LOG.debug("%s", vcardstr.get());
|
2005-11-05 23:04:33 +01:00
|
|
|
|
2006-06-01 20:05:34 +02:00
|
|
|
std::auto_ptr<VObject> vobj(VConverter::parse(vcardstr));
|
|
|
|
if (vobj.get() == 0) {
|
2008-08-09 12:26:52 +02:00
|
|
|
throwError(string("failure parsing contact " ) + uid);
|
2006-06-01 20:05:34 +02:00
|
|
|
}
|
|
|
|
|
2006-07-14 23:23:07 +02:00
|
|
|
vobj->toNativeEncoding();
|
|
|
|
|
2006-06-01 20:05:34 +02:00
|
|
|
for (int index = vobj->propertiesCount() - 1;
|
|
|
|
index >= 0;
|
|
|
|
index--) {
|
|
|
|
VProperty *vprop = vobj->getProperty(index);
|
2006-07-14 23:23:07 +02:00
|
|
|
|
|
|
|
// map ADR;TYPE=OTHER (not standard-compliant)
|
|
|
|
// to ADR;TYPE=PARCEL and vice-versa in preparseVCard();
|
|
|
|
// other TYPE=OTHER instances are simply removed
|
|
|
|
|
2006-06-01 20:05:34 +02:00
|
|
|
bool parcel = false;
|
|
|
|
|
|
|
|
int param = 0;
|
|
|
|
while (param < vprop->parameterCount()) {
|
|
|
|
if (!strcasecmp(vprop->getParameter(param), "TYPE") &&
|
|
|
|
!strcasecmp(vprop->getParameterValue(param), "OTHER")) {
|
|
|
|
vprop->removeParameter(param);
|
|
|
|
if (!strcasecmp(vprop->getName(), "ADR")) {
|
|
|
|
parcel = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
param++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parcel) {
|
|
|
|
vprop->addParameter("TYPE", "PARCEL");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-26 14:49:19 +02:00
|
|
|
// convert from 3.0 to 2.1?
|
|
|
|
if (m_vcardFormat == EVC_FORMAT_VCARD_21) {
|
2006-06-01 20:05:34 +02:00
|
|
|
LOG.debug("convert to 2.1");
|
|
|
|
|
2006-05-26 14:49:19 +02:00
|
|
|
// escape extended properties so that they are preserved
|
|
|
|
// as custom values by the server
|
|
|
|
for (int index = vobj->propertiesCount() - 1;
|
|
|
|
index >= 0;
|
|
|
|
index--) {
|
|
|
|
VProperty *vprop = vobj->getProperty(index);
|
|
|
|
string name = vprop->getName();
|
|
|
|
if (m_vcardExtensions.find(name) != m_vcardExtensions.end()) {
|
|
|
|
name = m_vcardExtensions.prefix + name;
|
|
|
|
vprop->setName(name.c_str());
|
|
|
|
}
|
2006-04-26 22:44:41 +02:00
|
|
|
|
2006-05-26 14:49:19 +02:00
|
|
|
// replace 3.0 ENCODING=B with 3.0 ENCODING=BASE64
|
|
|
|
char *encoding = vprop->getParameterValue("ENCODING");
|
|
|
|
if (encoding &&
|
|
|
|
!strcasecmp("B", encoding)) {
|
|
|
|
vprop->removeParameter("ENCODING");
|
|
|
|
vprop->addParameter("ENCODING", "BASE64");
|
2006-03-12 23:30:35 +01:00
|
|
|
}
|
2007-03-24 18:14:53 +01:00
|
|
|
|
|
|
|
// Workaround for Funambol 3.0 parser bug:
|
|
|
|
// trailing = are interpreted as soft line break
|
|
|
|
// even if the property doesn't use QUOTED-PRINTABLE encoding.
|
|
|
|
// Avoid that situation by enabling QUOTED-PRINTABLE for
|
|
|
|
// such properties.
|
|
|
|
if (!encoding) {
|
|
|
|
char *value = vprop->getValue();
|
|
|
|
|
|
|
|
if (value &&
|
|
|
|
value[0] &&
|
|
|
|
value[strlen(value)-1] == '=') {
|
|
|
|
vprop->addParameter("ENCODING", "QUOTED-PRINTABLE");
|
|
|
|
}
|
|
|
|
}
|
2007-11-08 23:18:59 +01:00
|
|
|
|
|
|
|
// Split TYPE=foo,bar into TYPE=foo;TYPE=bar because the comma-separated
|
|
|
|
// list is an extension of 3.0.
|
|
|
|
list<string> types;
|
|
|
|
while (true) {
|
|
|
|
char *type = vprop->getParameterValue("TYPE");
|
|
|
|
if (!type) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
StringBuffer buff(type);
|
|
|
|
|
|
|
|
char *token = strtok((char *)buff.c_str(), ",");
|
|
|
|
while (token != NULL) {
|
|
|
|
types.push_back(token);
|
|
|
|
token = strtok(NULL, ",");
|
|
|
|
}
|
|
|
|
vprop->removeParameter("TYPE");
|
|
|
|
}
|
2008-07-11 22:25:02 +02:00
|
|
|
BOOST_FOREACH(const string &type, types) {
|
|
|
|
vprop->addParameter("TYPE", type.c_str());
|
2007-11-08 23:18:59 +01:00
|
|
|
}
|
2007-11-30 23:40:33 +01:00
|
|
|
|
|
|
|
// Also make all strings uppercase because 3.0 is
|
|
|
|
// case-insensitive whereas 2.1 requires uppercase.
|
|
|
|
list< pair<string, string> > parameters;
|
|
|
|
while (vprop->parameterCount() > 0) {
|
|
|
|
const char *param = vprop->getParameter(0);
|
|
|
|
const char *value = vprop->getParameterValue(0);
|
|
|
|
if (!param || !value) {
|
|
|
|
break;
|
|
|
|
}
|
2008-03-29 16:41:11 +01:00
|
|
|
parameters.push_back(pair<string, string>(boost::to_upper_copy(string(param)), boost::to_upper_copy(string(value))));
|
2007-11-30 23:40:33 +01:00
|
|
|
vprop->removeParameter(0);
|
|
|
|
}
|
|
|
|
while (parameters.size() > 0) {
|
|
|
|
pair<string, string> param_value = parameters.front();
|
|
|
|
vprop->addParameter(param_value.first.c_str(), param_value.second.c_str());
|
|
|
|
parameters.pop_front();
|
|
|
|
}
|
2006-04-26 22:44:41 +02:00
|
|
|
}
|
2005-12-03 15:35:11 +01:00
|
|
|
|
2006-05-26 14:49:19 +02:00
|
|
|
vobj->setVersion("2.1");
|
|
|
|
VProperty *vprop = vobj->getProperty("VERSION");
|
|
|
|
vprop->setValue("2.1");
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2006-07-14 23:23:07 +02:00
|
|
|
vobj->fromNativeEncoding();
|
|
|
|
|
2006-06-10 14:26:44 +02:00
|
|
|
arrayptr<char> finalstr(vobj->toString(), "VOCL string");
|
2006-06-01 20:05:34 +02:00
|
|
|
LOG.debug("after conversion:");
|
2006-06-10 14:26:44 +02:00
|
|
|
LOG.debug("%s", (char *)finalstr);
|
2006-06-01 20:05:34 +02:00
|
|
|
|
2006-05-26 14:49:19 +02:00
|
|
|
auto_ptr<SyncItem> item( new SyncItem( uid.c_str() ) );
|
2006-10-03 13:44:34 +02:00
|
|
|
item->setData( (char *)finalstr, strlen(finalstr) );
|
2006-05-26 14:49:19 +02:00
|
|
|
item->setDataType( getMimeType() );
|
|
|
|
item->setModificationTime( 0 );
|
|
|
|
|
|
|
|
return item.release();
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2006-01-08 22:49:03 +01:00
|
|
|
string EvolutionContactSource::preparseVCard(SyncItem& item)
|
|
|
|
{
|
2008-04-07 19:59:17 +02:00
|
|
|
string data = (const char *)item.getData();
|
2006-01-08 22:49:03 +01:00
|
|
|
// convert to 3.0 to get rid of quoted-printable encoded
|
|
|
|
// non-ASCII chars, because Evolution does not support
|
|
|
|
// decoding them
|
2008-06-12 20:47:55 +02:00
|
|
|
LOG.debug("%s", data.c_str());
|
2006-01-08 22:49:03 +01:00
|
|
|
std::auto_ptr<VObject> vobj(VConverter::parse((char *)data.c_str()));
|
|
|
|
if (vobj.get() == 0) {
|
2008-08-09 12:26:52 +02:00
|
|
|
throwError(string("failure parsing contact " ) + item.getKey());
|
2006-01-08 22:49:03 +01:00
|
|
|
}
|
|
|
|
vobj->toNativeEncoding();
|
2006-03-12 23:30:35 +01:00
|
|
|
|
2006-09-09 10:36:04 +02:00
|
|
|
// - convert our escaped properties back
|
|
|
|
// - extend certain properties so that Evolution can parse them
|
|
|
|
// - ensure that unique properties appear indeed only once (because
|
|
|
|
// for some properties the server doesn't know that they have to be
|
|
|
|
// unique)
|
|
|
|
// - add X-EVOLUTION-UI-SLOT to TEL and MAIL properties (code just added
|
|
|
|
// for experiments, never enabled)
|
|
|
|
// - split TYPE=WORK,VOICE into TYPE=WORK;TYPE=VOICE
|
2006-03-18 15:18:14 +01:00
|
|
|
set<string> found;
|
2006-09-09 10:36:04 +02:00
|
|
|
|
|
|
|
#ifdef SET_UI_SLOT
|
|
|
|
class slots : public map< string, set<string> > {
|
|
|
|
public:
|
|
|
|
slots() {
|
|
|
|
insert(value_type(string("ADR"), set<string>()));
|
|
|
|
insert(value_type(string("EMAIL"), set<string>()));
|
|
|
|
insert(value_type(string("TEL"), set<string>()));
|
|
|
|
}
|
|
|
|
string assignFree(string type) {
|
|
|
|
int slot = 1;
|
|
|
|
set<string> &used((*this)[type]);
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
stringstream buffer;
|
|
|
|
buffer << slot;
|
|
|
|
string slotstr = buffer.str();
|
|
|
|
if (used.find(slotstr) == used.end()) {
|
|
|
|
used.insert(slotstr);
|
|
|
|
return slotstr;
|
|
|
|
}
|
|
|
|
slot++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} usedSlots;
|
|
|
|
#endif
|
|
|
|
|
2006-03-12 23:30:35 +01:00
|
|
|
for (int index = vobj->propertiesCount() - 1;
|
|
|
|
index >= 0;
|
|
|
|
index--) {
|
|
|
|
VProperty *vprop = vobj->getProperty(index);
|
|
|
|
string name = vprop->getName();
|
|
|
|
if (name.size() > m_vcardExtensions.prefix.size() &&
|
|
|
|
!name.compare(0, m_vcardExtensions.prefix.size(), m_vcardExtensions.prefix)) {
|
2006-03-18 15:18:14 +01:00
|
|
|
name = name.substr(m_vcardExtensions.prefix.size());
|
|
|
|
vprop->setName(name.c_str());
|
2006-06-26 22:24:23 +02:00
|
|
|
} else if (name == "ADR" || name == "EMAIL" || name == "TEL") {
|
2006-06-01 20:05:34 +02:00
|
|
|
const char *type = vprop->getParameterValue("TYPE");
|
2007-04-11 23:23:58 +02:00
|
|
|
bool isOther = false;
|
2006-06-26 22:24:23 +02:00
|
|
|
if (type) {
|
|
|
|
if (!strcasecmp(type, "PARCEL")) {
|
|
|
|
// remove unsupported TYPE=PARCEL that was
|
2007-04-11 23:23:58 +02:00
|
|
|
// added in createItem() and replace with "OTHER" to be symetric
|
2006-06-26 22:24:23 +02:00
|
|
|
vprop->removeParameter("TYPE");
|
2007-04-11 23:23:58 +02:00
|
|
|
isOther = true;
|
2006-06-26 22:24:23 +02:00
|
|
|
} else if (!strcasecmp(type, "PREF,VOICE")) {
|
|
|
|
// this is not mapped by Evolution to "Primary Phone",
|
|
|
|
// help a little bit
|
|
|
|
vprop->removeParameter("TYPE");
|
|
|
|
vprop->addParameter("TYPE", "PREF");
|
2006-09-09 10:36:04 +02:00
|
|
|
} else if (strchr(type, ',')) {
|
|
|
|
// Evolution cannot handle e.g. "WORK,VOICE". Split into
|
|
|
|
// different parts.
|
|
|
|
string buffer = type, value;
|
2008-03-24 22:42:47 +01:00
|
|
|
size_t start = 0, end;
|
2006-09-09 10:36:04 +02:00
|
|
|
vprop->removeParameter("TYPE");
|
|
|
|
while ((end = buffer.find(',', start)) != buffer.npos) {
|
|
|
|
value = buffer.substr(start, end - start);
|
|
|
|
vprop->addParameter("TYPE", value.c_str());
|
|
|
|
start = end + 1;
|
|
|
|
}
|
|
|
|
value = buffer.substr(start);
|
|
|
|
vprop->addParameter("TYPE", value.c_str());
|
2006-06-26 22:24:23 +02:00
|
|
|
}
|
2006-06-01 20:05:34 +02:00
|
|
|
}
|
|
|
|
|
2006-03-19 10:55:40 +01:00
|
|
|
// ensure that at least one TYPE is set
|
|
|
|
if (!vprop->containsParameter("TYPE") &&
|
2007-10-12 22:21:39 +02:00
|
|
|
|
|
|
|
/* TEL */
|
2007-10-04 22:45:49 +02:00
|
|
|
!vprop->containsParameter("CELL") &&
|
|
|
|
!vprop->containsParameter("CAR") &&
|
|
|
|
!vprop->containsParameter("PREF") &&
|
|
|
|
!vprop->containsParameter("FAX") &&
|
|
|
|
!vprop->containsParameter("VOICE") &&
|
2007-10-12 22:21:39 +02:00
|
|
|
!vprop->containsParameter("MSG") &&
|
|
|
|
!vprop->containsParameter("BBS") &&
|
|
|
|
!vprop->containsParameter("MODEM") &&
|
|
|
|
!vprop->containsParameter("ISDN") &&
|
|
|
|
!vprop->containsParameter("VIDEO") &&
|
2007-10-04 22:45:49 +02:00
|
|
|
!vprop->containsParameter("PAGER") &&
|
2007-10-12 22:21:39 +02:00
|
|
|
|
|
|
|
/* ADR */
|
|
|
|
!vprop->containsParameter("DOM") &&
|
|
|
|
!vprop->containsParameter("INTL") &&
|
|
|
|
!vprop->containsParameter("POSTAL") &&
|
|
|
|
!vprop->containsParameter("PARCEL") &&
|
|
|
|
|
|
|
|
/* EMAIL */
|
|
|
|
!vprop->containsParameter("AOL") &&
|
|
|
|
!vprop->containsParameter("AppleLink") &&
|
|
|
|
!vprop->containsParameter("ATTMail") &&
|
|
|
|
!vprop->containsParameter("CIS") &&
|
|
|
|
!vprop->containsParameter("eWorld") &&
|
2006-04-23 21:44:41 +02:00
|
|
|
!vprop->containsParameter("INTERNET") &&
|
2007-10-12 22:21:39 +02:00
|
|
|
!vprop->containsParameter("IBMMail") &&
|
|
|
|
!vprop->containsParameter("MCIMail") &&
|
|
|
|
!vprop->containsParameter("POWERSHARE") &&
|
|
|
|
!vprop->containsParameter("PRODIGY") &&
|
|
|
|
!vprop->containsParameter("TLX") &&
|
|
|
|
!vprop->containsParameter("X400") &&
|
|
|
|
|
|
|
|
/* all of them */
|
2006-03-19 10:55:40 +01:00
|
|
|
!vprop->containsParameter("HOME") &&
|
|
|
|
!vprop->containsParameter("WORK")) {
|
2007-04-11 23:23:58 +02:00
|
|
|
vprop->addParameter("TYPE", isOther ? "OTHER" : "HOME");
|
2006-03-12 23:30:35 +01:00
|
|
|
}
|
2006-09-09 10:36:04 +02:00
|
|
|
|
|
|
|
#ifdef SET_UI_SLOT
|
|
|
|
// remember which slots are set
|
|
|
|
const char *slot = vprop->getParameterValue("X-EVOLUTION-UI-SLOT");
|
|
|
|
if (slot) {
|
|
|
|
usedSlots[name].insert(slot);
|
|
|
|
}
|
|
|
|
#endif
|
2006-03-12 23:30:35 +01:00
|
|
|
}
|
2006-03-18 15:18:14 +01:00
|
|
|
|
2006-04-26 22:44:41 +02:00
|
|
|
// replace 2.1 ENCODING=BASE64 with 3.0 ENCODING=B
|
|
|
|
char *encoding = vprop->getParameterValue("ENCODING");
|
|
|
|
if (encoding &&
|
|
|
|
!strcasecmp("BASE64", encoding)) {
|
|
|
|
vprop->removeParameter("ENCODING");
|
|
|
|
vprop->addParameter("ENCODING", "B");
|
|
|
|
}
|
|
|
|
|
2006-03-18 15:18:14 +01:00
|
|
|
if (m_uniqueProperties.find(name) != m_uniqueProperties.end()) {
|
|
|
|
// has to be unique
|
|
|
|
if (found.find(name) != found.end()) {
|
|
|
|
// remove older entry
|
|
|
|
vobj->removeProperty(index);
|
|
|
|
} else {
|
|
|
|
// remember that valid instance exists
|
|
|
|
found.insert(name);
|
|
|
|
}
|
|
|
|
}
|
2006-03-12 23:30:35 +01:00
|
|
|
}
|
|
|
|
|
2006-09-09 10:36:04 +02:00
|
|
|
#ifdef SET_UI_SLOT
|
|
|
|
// add missing slot parameters
|
|
|
|
for (int index = 0;
|
|
|
|
index < vobj->propertiesCount();
|
|
|
|
index++) {
|
|
|
|
VProperty *vprop = vobj->getProperty(index);
|
|
|
|
string name = vprop->getName();
|
|
|
|
if (name == "EMAIL" || name == "TEL") {
|
|
|
|
const char *slot = vprop->getParameterValue("X-EVOLUTION-UI-SLOT");
|
|
|
|
|
|
|
|
if (!slot) {
|
|
|
|
string freeslot = usedSlots.assignFree(name);
|
|
|
|
vprop->addParameter("X-EVOLUTION-UI-SLOT", freeslot.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-01-08 22:49:03 +01:00
|
|
|
vobj->setVersion("3.0");
|
|
|
|
VProperty *vprop = vobj->getProperty("VERSION");
|
|
|
|
vprop->setValue("3.0");
|
|
|
|
vobj->fromNativeEncoding();
|
2006-06-10 14:26:44 +02:00
|
|
|
arrayptr<char> voclstr(vobj->toString(), "VOCL string");
|
|
|
|
data = (char *)voclstr;
|
2006-01-08 22:49:03 +01:00
|
|
|
LOG.debug("after conversion to 3.0:");
|
2006-06-10 14:26:44 +02:00
|
|
|
LOG.debug("%s", data.c_str());
|
2006-01-08 22:49:03 +01:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2006-04-09 13:48:11 +02:00
|
|
|
void EvolutionContactSource::setItemStatusThrow(const char *key, int status)
|
2006-01-23 22:51:43 +01:00
|
|
|
{
|
|
|
|
switch (status) {
|
|
|
|
case STC_CONFLICT_RESOLVED_WITH_SERVER_DATA: {
|
|
|
|
// make a copy before allowing the server to overwrite it
|
|
|
|
|
2006-05-25 19:32:07 +02:00
|
|
|
LOG.error("%s: contact %s: conflict, will be replaced by server contact - create copy",
|
|
|
|
getName(), key);
|
2006-01-23 22:51:43 +01:00
|
|
|
|
|
|
|
EContact *contact;
|
|
|
|
GError *gerror = NULL;
|
|
|
|
if (! e_book_get_contact( m_addressbook,
|
|
|
|
key,
|
|
|
|
&contact,
|
|
|
|
&gerror ) ) {
|
2006-05-25 19:32:07 +02:00
|
|
|
LOG.error("%s: item %.80s: reading original for copy failed",
|
|
|
|
getName(), key);
|
2006-01-23 22:51:43 +01:00
|
|
|
break;
|
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<EContact, GObject> contactptr( contact, "contact" );
|
2006-01-23 22:51:43 +01:00
|
|
|
EContact *copy = e_contact_duplicate(contact);
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<EContact, GObject> contactcopyptr(copy);
|
2006-01-23 22:51:43 +01:00
|
|
|
if(!copy ||
|
|
|
|
! e_book_add_contact(m_addressbook,
|
|
|
|
copy,
|
|
|
|
&gerror)) {
|
2006-05-25 19:32:07 +02:00
|
|
|
LOG.error("%s: item %.80s: making copy failed",
|
|
|
|
getName(), key);
|
2006-01-23 22:51:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2006-04-09 13:48:11 +02:00
|
|
|
EvolutionSyncSource::setItemStatusThrow(key, status);
|
2006-01-23 22:51:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-17 11:41:37 +02:00
|
|
|
int EvolutionContactSource::addItemThrow(SyncItem& item)
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
2006-04-17 11:41:37 +02:00
|
|
|
int status = STC_OK;
|
2006-04-09 13:48:11 +02:00
|
|
|
string data;
|
|
|
|
if( strcmp(item.getDataType(), "raw" ) ) {
|
|
|
|
data = preparseVCard(item);
|
|
|
|
} else {
|
|
|
|
data = (const char *)item.getData();
|
|
|
|
}
|
2006-08-14 22:52:34 +02:00
|
|
|
eptr<EContact, GObject> contact(e_contact_new_from_vcard(data.c_str()));
|
2006-04-09 13:48:11 +02:00
|
|
|
if( contact ) {
|
|
|
|
GError *gerror = NULL;
|
|
|
|
e_contact_set(contact, E_CONTACT_UID, NULL);
|
|
|
|
if (e_book_add_contact(m_addressbook, contact, &gerror)) {
|
|
|
|
item.setKey( (const char *)e_contact_get_const( contact, E_CONTACT_UID ) );
|
2005-11-05 23:04:33 +01:00
|
|
|
} else {
|
2006-04-09 13:48:11 +02:00
|
|
|
throwError( "storing new contact", gerror );
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-04-09 13:48:11 +02:00
|
|
|
} else {
|
2008-08-09 12:26:52 +02:00
|
|
|
throwError(string("failure parsing vcard " ) + data);
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-04-17 11:41:37 +02:00
|
|
|
return status;
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2006-04-17 11:41:37 +02:00
|
|
|
int EvolutionContactSource::updateItemThrow(SyncItem& item)
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
2006-04-17 11:41:37 +02:00
|
|
|
int status = STC_OK;
|
2006-04-09 13:48:11 +02:00
|
|
|
string data = preparseVCard(item);
|
2006-08-14 22:52:34 +02:00
|
|
|
eptr<EContact, GObject> contact(e_contact_new_from_vcard(data.c_str()));
|
2006-04-09 13:48:11 +02:00
|
|
|
if( contact ) {
|
|
|
|
GError *gerror = NULL;
|
|
|
|
|
|
|
|
// The following code commits the new_from_vcard contact using the
|
|
|
|
// existing UID. It has been observed in Evolution 2.0.4 that the
|
|
|
|
// changes were then not "noticed" properly by the Evolution GUI.
|
|
|
|
//
|
|
|
|
// The code below was supposed to "notify" Evolution of the change by
|
|
|
|
// loaded the updated contact, modifying it, committing, restoring
|
|
|
|
// and committing once more, but that did not solve the problem.
|
|
|
|
//
|
|
|
|
// TODO: test with current Evolution
|
2006-11-27 22:08:12 +01:00
|
|
|
e_contact_set( contact, E_CONTACT_UID, (void *)item.getKey() );
|
2006-04-09 13:48:11 +02:00
|
|
|
if ( e_book_commit_contact(m_addressbook, contact, &gerror) ) {
|
|
|
|
const char *uid = (const char *)e_contact_get_const(contact, E_CONTACT_UID);
|
|
|
|
if (uid) {
|
|
|
|
item.setKey( uid );
|
|
|
|
}
|
2006-01-23 22:51:43 +01:00
|
|
|
|
|
|
|
#if 0
|
2006-04-09 13:48:11 +02:00
|
|
|
EContact *refresh_contact;
|
|
|
|
if (! e_book_get_contact( m_addressbook,
|
|
|
|
uid,
|
|
|
|
&refresh_contact,
|
|
|
|
&gerror ) ) {
|
2006-09-10 10:06:17 +02:00
|
|
|
throwError( string( "reading refresh contact " ) + uid,
|
2006-04-09 13:48:11 +02:00
|
|
|
gerror );
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<EContact, GObject> contactptr( refresh_contact, "contact" );
|
2006-04-09 13:48:11 +02:00
|
|
|
string nick = (const char *)e_contact_get_const(refresh_contact, E_CONTACT_NICKNAME);
|
|
|
|
string nick_mod = nick + "_";
|
|
|
|
e_contact_set(refresh_contact, E_CONTACT_NICKNAME, (void *)nick_mod.c_str());
|
|
|
|
e_book_commit_contact(m_addressbook, refresh_contact, &gerror);
|
|
|
|
e_contact_set(refresh_contact, E_CONTACT_NICKNAME, (void *)nick.c_str());
|
|
|
|
e_book_commit_contact(m_addressbook, refresh_contact, &gerror);
|
|
|
|
#endif
|
2005-11-05 23:04:33 +01:00
|
|
|
} else {
|
2006-09-10 10:06:17 +02:00
|
|
|
throwError( string( "updating contact " ) + item.getKey(), gerror );
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-04-09 13:48:11 +02:00
|
|
|
} else {
|
2008-08-09 12:26:52 +02:00
|
|
|
throwError(string("failure parsing vcard " ) + data);
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-04-17 11:41:37 +02:00
|
|
|
return status;
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2006-04-17 11:41:37 +02:00
|
|
|
int EvolutionContactSource::deleteItemThrow(SyncItem& item)
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
2006-04-17 11:41:37 +02:00
|
|
|
int status = STC_OK;
|
2006-04-09 13:48:11 +02:00
|
|
|
GError *gerror = NULL;
|
|
|
|
if (!e_book_remove_contact( m_addressbook, item.getKey(), &gerror ) ) {
|
2006-09-10 16:43:38 +02:00
|
|
|
if (gerror->domain == E_BOOK_ERROR &&
|
|
|
|
gerror->code == E_BOOK_ERROR_CONTACT_NOT_FOUND) {
|
|
|
|
LOG.debug("%s: %s: request to delete non-existant contact ignored",
|
|
|
|
getName(), item.getKey());
|
|
|
|
g_clear_error(&gerror);
|
|
|
|
} else {
|
|
|
|
throwError( string( "deleting contact " ) + item.getKey(),
|
|
|
|
gerror );
|
|
|
|
}
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
2006-04-17 11:41:37 +02:00
|
|
|
return status;
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
|
2008-03-06 23:23:13 +01:00
|
|
|
const char *EvolutionContactSource::getMimeType() const
|
2005-11-05 23:04:33 +01:00
|
|
|
{
|
|
|
|
switch( m_vcardFormat ) {
|
|
|
|
case EVC_FORMAT_VCARD_21:
|
2006-04-12 23:01:40 +02:00
|
|
|
return "text/x-vcard";
|
2005-11-05 23:04:33 +01:00
|
|
|
break;
|
|
|
|
case EVC_FORMAT_VCARD_30:
|
2006-04-26 22:44:41 +02:00
|
|
|
default:
|
2005-11-05 23:04:33 +01:00
|
|
|
return "text/vcard";
|
2006-04-26 22:44:41 +02:00
|
|
|
break;
|
2005-11-05 23:04:33 +01:00
|
|
|
}
|
|
|
|
}
|
2005-12-03 15:35:11 +01:00
|
|
|
|
2008-03-06 23:23:13 +01:00
|
|
|
const char *EvolutionContactSource::getMimeVersion() const
|
2006-09-07 21:47:29 +02:00
|
|
|
{
|
|
|
|
switch( m_vcardFormat ) {
|
|
|
|
case EVC_FORMAT_VCARD_21:
|
|
|
|
return "2.1";
|
|
|
|
break;
|
|
|
|
case EVC_FORMAT_VCARD_30:
|
|
|
|
default:
|
|
|
|
return "3.0";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-11 17:00:37 +01:00
|
|
|
void EvolutionContactSource::logItem(const string &uid, const string &info, bool debug)
|
2005-12-03 15:35:11 +01:00
|
|
|
{
|
2006-11-11 17:00:37 +01:00
|
|
|
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
|
2005-12-03 15:35:11 +01:00
|
|
|
string line;
|
|
|
|
EContact *contact;
|
|
|
|
GError *gerror = NULL;
|
|
|
|
|
|
|
|
if (e_book_get_contact( m_addressbook,
|
|
|
|
uid.c_str(),
|
|
|
|
&contact,
|
|
|
|
&gerror )) {
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<EContact, GObject> contactptr(contact);
|
|
|
|
|
2005-12-04 20:49:31 +01:00
|
|
|
const char *fileas = (const char *)e_contact_get_const( contact, E_CONTACT_FILE_AS );
|
2006-06-12 22:59:27 +02:00
|
|
|
if (fileas) {
|
|
|
|
line += fileas;
|
|
|
|
} else {
|
|
|
|
const char *name = (const char *)e_contact_get_const( contact, E_CONTACT_FULL_NAME );
|
|
|
|
if (name) {
|
|
|
|
line += name;
|
|
|
|
} else {
|
|
|
|
line += "<unnamed contact>";
|
|
|
|
}
|
|
|
|
}
|
2005-12-03 15:35:11 +01:00
|
|
|
} else {
|
2008-03-18 14:36:59 +01:00
|
|
|
g_clear_error(&gerror);
|
2006-06-26 22:28:09 +02:00
|
|
|
line += "<name unavailable>";
|
2005-12-03 15:35:11 +01:00
|
|
|
}
|
|
|
|
line += " (";
|
|
|
|
line += uid;
|
|
|
|
line += "): ";
|
|
|
|
line += info;
|
|
|
|
|
2006-11-11 17:00:37 +01:00
|
|
|
(LOG.*(debug ? &Log::debug : &Log::info))( "%s: %s", getName(), line.c_str() );
|
2005-12-03 15:35:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-07 19:59:17 +02:00
|
|
|
void EvolutionContactSource::logItem(const SyncItem &item, const string &info, bool debug)
|
2005-12-03 15:35:11 +01:00
|
|
|
{
|
2006-11-11 17:00:37 +01:00
|
|
|
if (LOG.getLevel() >= (debug ? LOG_LEVEL_DEBUG : LOG_LEVEL_INFO)) {
|
2005-12-03 15:35:11 +01:00
|
|
|
string line;
|
2005-12-12 20:15:13 +01:00
|
|
|
const char *data = (const char *)item.getData();
|
|
|
|
int datasize = item.getDataSize();
|
|
|
|
if (datasize <= 0) {
|
|
|
|
data = "";
|
|
|
|
datasize = 0;
|
|
|
|
}
|
|
|
|
string vcard( data, datasize );
|
2005-12-03 15:35:11 +01:00
|
|
|
|
2006-06-11 22:07:26 +02:00
|
|
|
size_t offset = vcard.find( "FN:");
|
2005-12-03 15:35:11 +01:00
|
|
|
if (offset != vcard.npos) {
|
2008-06-28 21:55:56 +02:00
|
|
|
// accept both "\r\n" and "\n" as line termination:
|
|
|
|
// "\r\n" is the standard, but MemoToo does not follow that
|
|
|
|
int len = vcard.find_first_of("\r\n", offset) - offset - 3;
|
2005-12-03 15:35:11 +01:00
|
|
|
line += vcard.substr( offset + 3, len );
|
|
|
|
} else {
|
2006-06-26 22:28:09 +02:00
|
|
|
line += "<unnamed contact>";
|
2005-12-03 15:35:11 +01:00
|
|
|
}
|
|
|
|
|
2005-12-04 20:49:31 +01:00
|
|
|
if (!item.getKey() ) {
|
|
|
|
line += ", NULL UID (?!)";
|
|
|
|
} else if (!strlen( item.getKey() )) {
|
|
|
|
line += ", empty UID";
|
2005-12-03 15:35:11 +01:00
|
|
|
} else {
|
|
|
|
line += ", ";
|
|
|
|
line += item.getKey();
|
|
|
|
|
|
|
|
EContact *contact;
|
|
|
|
GError *gerror = NULL;
|
|
|
|
if (e_book_get_contact( m_addressbook,
|
|
|
|
item.getKey(),
|
|
|
|
&contact,
|
|
|
|
&gerror )) {
|
2008-03-18 14:36:59 +01:00
|
|
|
eptr<EContact, GObject> contactptr( contact, "contact" );
|
|
|
|
|
2006-06-12 22:59:27 +02:00
|
|
|
line += ", EV ";
|
2005-12-04 20:49:31 +01:00
|
|
|
const char *fileas = (const char *)e_contact_get_const( contact, E_CONTACT_FILE_AS );
|
2006-06-12 22:59:27 +02:00
|
|
|
if (fileas) {
|
|
|
|
line += fileas;
|
|
|
|
} else {
|
|
|
|
const char *name = (const char *)e_contact_get_const( contact, E_CONTACT_FULL_NAME );
|
|
|
|
if (name) {
|
|
|
|
line += name;
|
|
|
|
} else {
|
|
|
|
line += "<unnamed contact>";
|
|
|
|
}
|
|
|
|
}
|
2005-12-03 15:35:11 +01:00
|
|
|
} else {
|
|
|
|
line += ", not in Evolution";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
line += ": ";
|
|
|
|
line += info;
|
|
|
|
|
2006-11-11 17:00:37 +01:00
|
|
|
(LOG.*(debug ? &Log::debug : &Log::info))( "%s: %s", getName(), line.c_str() );
|
2005-12-03 15:35:11 +01:00
|
|
|
}
|
|
|
|
}
|
2006-01-08 22:49:03 +01:00
|
|
|
|
2006-07-27 21:41:24 +02:00
|
|
|
#endif /* ENABLE_EBOOK */
|
2008-03-10 23:45:36 +01:00
|
|
|
|
|
|
|
#ifdef ENABLE_MODULES
|
|
|
|
# include "EvolutionContactSourceRegister.cpp"
|
|
|
|
#endif
|