EDS: memo syncing as iCalendar 2.0 (FDO #52714)
When syncing memos with a peer which also supports iCalendar 2.0 as data format, the engine will now pick iCalendar 2.0 instead of converting to/from plain text. The advantage is that some additional properties like start date and categories can also be synchronized. The code is a lot simpler, too, because the EDS specific iCalendar 2.0 <-> text conversion code can be removed.
This commit is contained in:
parent
adf2522ad1
commit
6770237424
|
@ -1,255 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2009 Patrick Ohly <patrick.ohly@gmx.de>
|
||||
* Copyright (C) 2009 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) version 3.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
using namespace std;
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_ECAL
|
||||
|
||||
#include "EvolutionMemoSource.h"
|
||||
|
||||
#include <syncevo/Logging.h>
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
SE_BEGIN_CXX
|
||||
|
||||
void EvolutionMemoSource::readItem(const string &luid, std::string &item, bool raw)
|
||||
{
|
||||
if (raw) {
|
||||
EvolutionCalendarSource::readItem(luid, item, false);
|
||||
return;
|
||||
}
|
||||
|
||||
ItemID id(luid);
|
||||
eptr<icalcomponent> comp(retrieveItem(id));
|
||||
icalcomponent *cal = icalcomponent_get_first_component(comp, ICAL_VCALENDAR_COMPONENT);
|
||||
if (!cal) {
|
||||
cal = comp;
|
||||
}
|
||||
icalcomponent *journal = icalcomponent_get_first_component(cal, ICAL_VJOURNAL_COMPONENT);
|
||||
if (!journal) {
|
||||
journal = comp;
|
||||
}
|
||||
icalproperty *summaryprop = icalcomponent_get_first_property(journal, ICAL_SUMMARY_PROPERTY);
|
||||
string summary;
|
||||
if (summaryprop) {
|
||||
const char *summaryptr = icalproperty_get_summary(summaryprop);
|
||||
if (summaryptr) {
|
||||
summary = summaryptr;
|
||||
}
|
||||
}
|
||||
icalproperty *desc = icalcomponent_get_first_property(journal, ICAL_DESCRIPTION_PROPERTY);
|
||||
if (desc) {
|
||||
const char *text = icalproperty_get_description(desc);
|
||||
if (text) {
|
||||
size_t len = strlen(text);
|
||||
bool insertSummary = false;
|
||||
const char *eol;
|
||||
|
||||
// Check the first line: if it is the same as the summary,
|
||||
// then ignore the summary. Otherwise include the summary
|
||||
// as first line in the text body. At a receiving Evolution
|
||||
// the summary will remain part of the text for compatibility
|
||||
// with other clients which might use the first line as part
|
||||
// of the normal text.
|
||||
eol = strchr(text, '\n');
|
||||
if (!eol) {
|
||||
eol = text + len;
|
||||
}
|
||||
if (summary.size() &&
|
||||
summary.compare(0, summary.size(), text, eol - text)) {
|
||||
insertSummary = true;
|
||||
}
|
||||
|
||||
// Replace all \n with \r\n: in the worst case the text
|
||||
// becomes twice as long. Also make room for summary.
|
||||
eptr<char> dostext((char *)malloc(len * 2 + 1 +
|
||||
(insertSummary ? summary.size() + 2 : 0)));
|
||||
const char *from = text;
|
||||
char *to = dostext;
|
||||
if (insertSummary) {
|
||||
memcpy(to, summary.c_str(), summary.size());
|
||||
memcpy(to + summary.size(), "\r\n", 2);
|
||||
to += summary.size() + 2;
|
||||
}
|
||||
eol = strchr(from, '\n');
|
||||
while (eol) {
|
||||
size_t linelen = eol - from;
|
||||
memcpy(to, from, linelen);
|
||||
to += linelen;
|
||||
from += linelen;
|
||||
to[0] = '\r';
|
||||
to[1] = '\n';
|
||||
to += 2;
|
||||
from++;
|
||||
|
||||
eol = strchr(from, '\n');
|
||||
}
|
||||
memcpy(to, from, strlen(from) + 1);
|
||||
item = dostext.get();
|
||||
}
|
||||
}
|
||||
|
||||
if (item.empty()) {
|
||||
// no description, use summary
|
||||
item = summary;
|
||||
}
|
||||
}
|
||||
|
||||
EvolutionCalendarSource::InsertItemResult EvolutionMemoSource::insertItem(const string &luid, const std::string &item, bool raw)
|
||||
{
|
||||
if (raw) {
|
||||
return EvolutionCalendarSource::insertItem(luid, item, false);
|
||||
}
|
||||
|
||||
bool update = !luid.empty();
|
||||
InsertItemResultState state = ITEM_OKAY;
|
||||
string newluid = luid;
|
||||
string modTime;
|
||||
|
||||
eptr<char> text;
|
||||
text.set((char *)malloc(item.size() + 1), "copy of item");
|
||||
memcpy(text, item.c_str(), item.size());
|
||||
text.get()[item.size()] = 0;
|
||||
|
||||
// replace all \r\n with \n
|
||||
char *from = text, *to = text;
|
||||
const char *eol = strstr(from, "\r\n");
|
||||
while (eol) {
|
||||
size_t linelen = eol - from;
|
||||
if (to != from) {
|
||||
memmove(to, from, linelen);
|
||||
}
|
||||
to += linelen;
|
||||
from += linelen;
|
||||
*to = '\n';
|
||||
to++;
|
||||
from += 2;
|
||||
|
||||
eol = strstr(from, "\r\n");
|
||||
}
|
||||
if (to != from) {
|
||||
memmove(to, from, strlen(from) + 1);
|
||||
}
|
||||
|
||||
eol = strchr(text, '\n');
|
||||
string summary;
|
||||
if (eol) {
|
||||
summary.insert(0, (char *)text, eol - (char *)text);
|
||||
} else {
|
||||
summary = (char *)text;
|
||||
}
|
||||
|
||||
eptr<icalcomponent> subcomp(icalcomponent_vanew(
|
||||
ICAL_VJOURNAL_COMPONENT,
|
||||
icalproperty_new_summary(summary.c_str()),
|
||||
icalproperty_new_description(text),
|
||||
0));
|
||||
|
||||
if( !subcomp ) {
|
||||
throwError(SE_HERE, string("failure creating vjournal " ) + summary);
|
||||
}
|
||||
|
||||
GErrorCXX gerror;
|
||||
if (!update) {
|
||||
const char *uid = NULL;
|
||||
#ifdef USE_EDS_CLIENT
|
||||
// UID only needs to be freed in ECalClient API
|
||||
PlainGStr uidOwner;
|
||||
#endif
|
||||
|
||||
if (
|
||||
#ifdef USE_EDS_CLIENT
|
||||
!e_cal_client_create_object_sync(m_calendar, subcomp, (gchar **)&uid, NULL, gerror)
|
||||
#else
|
||||
!e_cal_create_object(m_calendar, subcomp, (gchar **)&uid, gerror)
|
||||
#endif
|
||||
) {
|
||||
if (
|
||||
#ifdef USE_EDS_CLIENT
|
||||
gerror->domain == E_CAL_CLIENT_ERROR &&
|
||||
gerror->code == E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS
|
||||
#else
|
||||
gerror->domain == E_CALENDAR_ERROR &&
|
||||
gerror->code == E_CALENDAR_STATUS_OBJECT_ID_ALREADY_EXISTS
|
||||
#endif
|
||||
) {
|
||||
// Deal with error due to adding already existing item.
|
||||
// Should never happen for plain text journal entries because
|
||||
// they have no embedded ID, but who knows...
|
||||
state = ITEM_NEEDS_MERGE;
|
||||
uid = icalcomponent_get_uid(subcomp);
|
||||
if (!uid) {
|
||||
throwError(SE_HERE, "storing new memo item, no UID set", gerror);
|
||||
}
|
||||
} else {
|
||||
throwError(SE_HERE, "storing new memo item", gerror);
|
||||
}
|
||||
}
|
||||
#ifdef USE_EDS_CLIENT
|
||||
else {
|
||||
uidOwner = PlainGStr((gchar *)uid);
|
||||
}
|
||||
#endif
|
||||
ItemID id(uid, "");
|
||||
newluid = id.getLUID();
|
||||
if (state != ITEM_NEEDS_MERGE) {
|
||||
modTime = getItemModTime(id);
|
||||
}
|
||||
} else {
|
||||
ItemID id(newluid);
|
||||
|
||||
// ensure that the component has the right UID
|
||||
if (update && !id.m_uid.empty()) {
|
||||
icalcomponent_set_uid(subcomp, id.m_uid.c_str());
|
||||
}
|
||||
|
||||
if (
|
||||
#ifdef USE_EDS_CLIENT
|
||||
!e_cal_client_modify_object_sync(m_calendar, subcomp, CALOBJ_MOD_ALL,
|
||||
NULL, gerror)
|
||||
#else
|
||||
!e_cal_modify_object(m_calendar, subcomp, CALOBJ_MOD_ALL, gerror)
|
||||
#endif
|
||||
) {
|
||||
throwError(SE_HERE, string("updating memo item ") + luid, gerror);
|
||||
}
|
||||
ItemID newid = getItemID(subcomp);
|
||||
newluid = newid.getLUID();
|
||||
modTime = getItemModTime(newid);
|
||||
}
|
||||
|
||||
return InsertItemResult(newluid, modTime, state);
|
||||
}
|
||||
|
||||
bool EvolutionMemoSource::isNativeType(const char *type)
|
||||
{
|
||||
return type &&
|
||||
(!strcasecmp(type, "raw") ||
|
||||
!strcasecmp(type, "text/x-vcalendar") ||
|
||||
!strcasecmp(type, "text/calendar"));
|
||||
}
|
||||
|
||||
SE_END_CXX
|
||||
|
||||
#endif /* ENABLE_ECAL */
|
||||
|
|
@ -43,13 +43,8 @@ class EvolutionMemoSource : public EvolutionCalendarSource
|
|||
//
|
||||
// implementation of SyncSource
|
||||
//
|
||||
virtual InsertItemResult insertItem(const string &uid, const std::string &item, bool raw);
|
||||
void readItem(const std::string &luid, std::string &item, bool raw);
|
||||
virtual std::string getMimeType() const { return "text/plain"; }
|
||||
virtual std::string getMimeVersion() const { return "1.0"; }
|
||||
|
||||
private:
|
||||
bool isNativeType(const char *type);
|
||||
virtual std::string getMimeType() const { return "text/calendar+plain"; }
|
||||
virtual std::string getMimeVersion() const { return "2.0"; }
|
||||
};
|
||||
|
||||
#endif // ENABLE_ECAL
|
||||
|
|
|
@ -15,7 +15,7 @@ src_backends_evolution_syncecal_src = \
|
|||
src/backends/evolution/EvolutionCalendarSource.h \
|
||||
src/backends/evolution/EvolutionMemoSource.h \
|
||||
src/backends/evolution/EvolutionCalendarSource.cpp \
|
||||
src/backends/evolution/EvolutionMemoSource.cpp
|
||||
$(NOP)
|
||||
|
||||
if ENABLE_ECAL
|
||||
src_backends_evolution_syncecal_src += \
|
||||
|
|
Loading…
Reference in New Issue