[evolution-data-server] Bug #586342 - CalDAV backend does not support attachments
- From: Milan Crha <mcrha src gnome org>
- To: svn-commits-list gnome org
- Subject: [evolution-data-server] Bug #586342 - CalDAV backend does not support attachments
- Date: Tue, 14 Jul 2009 11:31:01 +0000 (UTC)
commit 0b634822df5d9e145e119620741f04c2d455f66d
Author: Wang Xin <jedy wang sun com>
Date: Tue Jul 14 13:29:40 2009 +0200
Bug #586342 - CalDAV backend does not support attachments
calendar/backends/caldav/e-cal-backend-caldav.c | 294 +++++++++++++++++++++--
calendar/libecal/e-cal.c | 8 +
2 files changed, 286 insertions(+), 16 deletions(-)
---
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index 404fd62..b3e5c9d 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
#include <gconf/gconf-client.h>
+#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
#include "libedataserver/e-xml-hash-utils.h"
#include "libedataserver/e-proxy.h"
@@ -51,6 +52,7 @@
#define CALDAV_CTAG_KEY "CALDAV_CTAG"
#define CALDAV_MAX_MULTIGET_AMOUNT 100 /* what's the maximum count of items to fetch within a multiget request */
+#define LOCAL_PREFIX "file://"
/* in seconds */
#define DEFAULT_REFRESH_TIME 60
@@ -72,6 +74,9 @@ struct _ECalBackendCalDAVPrivate {
/* The local disk cache */
ECalBackendCache *cache;
+ /* local attachments store */
+ gchar *local_attachments_store;
+
/* should we sync for offline mode? */
gboolean do_offline;
@@ -134,6 +139,10 @@ struct _ECalBackendCalDAVPrivate {
#define DEBUG_MESSAGE_BODY "message:body"
#define DEBUG_SERVER_ITEMS "items"
+static void convert_to_inline_attachment (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp);
+static void convert_to_url_attachment (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp);
+static void remove_cached_attachment (ECalBackendCalDAV *cbdav, const gchar *uid);
+
static gboolean caldav_debug_all = FALSE;
static GHashTable *caldav_debug_table = NULL;
@@ -263,6 +272,7 @@ static gboolean put_comp_to_cache (ECalBackendCalDAV *cbdav, icalcomponent *ical
/* ************************************************************************* */
/* Misc. utility functions */
#define X_E_CALDAV "X-EVOLUTION-CALDAV-"
+#define X_E_CALDAV_ATTACHMENT_NAME X_E_CALDAV "ATTACHMENT-NAME"
static void
icomp_x_prop_set (icalcomponent *comp, const gchar *key, const gchar *value)
@@ -1606,6 +1616,7 @@ remove_complist_from_cache_and_notify_cb (gpointer key, gpointer value, gpointer
e_cal_component_free_id (id);
}
+ remove_cached_attachment (cbdav, (const char *)key);
return FALSE;
}
@@ -1826,6 +1837,7 @@ synchronize_cache (ECalBackendCalDAV *cbdav, time_t start_time, time_t end_time)
subcomp = icalcomponent_get_next_component (icomp, kind)) {
ECalComponent *new_comp, *old_comp;
+ convert_to_url_attachment (cbdav, subcomp);
new_comp = e_cal_component_new ();
if (e_cal_component_set_icalcomponent (new_comp, icalcomponent_new_clone (subcomp))) {
const gchar *uid = NULL;
@@ -2076,11 +2088,15 @@ initialize_backend (ECalBackendCalDAV *cbdav)
{
ECalBackendSyncStatus result;
ECalBackendCalDAVPrivate *priv;
+ ECalSourceType source_type;
ESource *source;
const gchar *os_val;
const gchar *uri;
gsize len;
- const gchar *refresh;
+ const gchar *refresh;
+ const gchar *stype;
+ gchar *filename;
+ gchar *mangled_uri;
priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
@@ -2157,29 +2173,44 @@ initialize_backend (ECalBackendCalDAV *cbdav)
g_free (tmp);
}
- if (priv->cache == NULL) {
- ECalSourceType source_type;
-
- switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbdav))) {
- default:
- case ICAL_VEVENT_COMPONENT:
- source_type = E_CAL_SOURCE_TYPE_EVENT;
- break;
- case ICAL_VTODO_COMPONENT:
- source_type = E_CAL_SOURCE_TYPE_TODO;
- break;
- case ICAL_VJOURNAL_COMPONENT:
- source_type = E_CAL_SOURCE_TYPE_JOURNAL;
- break;
- }
+ switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbdav))) {
+ default:
+ case ICAL_VEVENT_COMPONENT:
+ source_type = E_CAL_SOURCE_TYPE_EVENT;
+ stype = "calendar";
+ break;
+ case ICAL_VTODO_COMPONENT:
+ source_type = E_CAL_SOURCE_TYPE_TODO;
+ stype = "tasks";
+ break;
+ case ICAL_VJOURNAL_COMPONENT:
+ source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+ stype = "journal";
+ break;
+ }
+ if (priv->cache == NULL) {
priv->cache = e_cal_backend_cache_new (priv->uri, source_type);
if (priv->cache == NULL) {
result = GNOME_Evolution_Calendar_OtherError;
goto out;
}
+ }
+ /* Set the local attachment store */
+ mangled_uri = g_strdup (uri);
+ mangled_uri = g_strdelimit (mangled_uri, ":/", '_');
+ filename = g_build_filename (g_get_home_dir (),
+ ".evolution", "cache", stype,
+ mangled_uri, NULL);
+ g_free (mangled_uri);
+ if (priv->local_attachments_store)
+ g_free (priv->local_attachments_store);
+ priv->local_attachments_store = filename;
+ if (g_mkdir_with_parents (filename, 0700) < 0) {
+ result = GNOME_Evolution_Calendar_OtherError;
+ goto out;
}
refresh = e_source_get_property (source, "refresh");
@@ -2564,6 +2595,229 @@ strip_x_evolution_caldav (icalcomponent *icomp)
g_slist_free (to_remove);
}
+static void
+convert_to_inline_attachment (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp)
+{
+ ECalBackendCalDAVPrivate *priv;
+ icalcomponent *cclone;
+ icalproperty *p;
+ GSList *to_remove = NULL;
+
+ g_return_if_fail (icalcomp != NULL);
+
+ cclone = icalcomponent_new_clone (icalcomp);
+
+ /* Remove local url attachments first */
+ for (p = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
+ p;
+ p = icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY)) {
+ icalattach *attach;
+
+ attach = icalproperty_get_attach ((const icalproperty *)p);
+ if (icalattach_get_is_url (attach)) {
+ const gchar *url;
+
+ url = icalattach_get_url (attach);
+ if (g_str_has_prefix (url, LOCAL_PREFIX))
+ to_remove = g_slist_prepend (to_remove, p);
+ }
+ }
+ g_slist_foreach (to_remove, remove_property, icalcomp);
+ g_slist_free (to_remove);
+
+ /* convert local url attachments to inline attachments now */
+ priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+ for (p = icalcomponent_get_first_property (cclone, ICAL_ATTACH_PROPERTY);
+ p;
+ p = icalcomponent_get_next_property (cclone, ICAL_ATTACH_PROPERTY)) {
+ icalattach *attach;
+ GFile *file;
+ GError *error = NULL;
+ const gchar *uri;
+ gchar *basename;
+ gchar *content;
+ gsize len;
+
+ attach = icalproperty_get_attach ((const icalproperty *)p);
+ if (!icalattach_get_is_url (attach))
+ continue;
+
+ uri = icalattach_get_url (attach);
+ if (!g_str_has_prefix (uri, LOCAL_PREFIX))
+ continue;
+
+ file = g_file_new_for_uri (uri);
+ basename = g_file_get_basename (file);
+ if (g_file_load_contents (file, NULL, &content, &len, NULL, &error) == TRUE) {
+ icalproperty *prop;
+ icalparameter *param;
+ gchar *encoded;
+
+ /*
+ * do a base64 encoding so it can
+ * be embedded in a soap message
+ */
+ encoded = g_base64_encode ((guchar *) content, len);
+ attach = icalattach_new_from_data ((guchar *) encoded, 0, 0);
+ g_free(content);
+ g_free(encoded);
+
+ prop = icalproperty_new_attach (attach);
+ icalattach_unref (attach);
+
+ param = icalparameter_new_value (ICAL_VALUE_BINARY);
+ icalproperty_add_parameter (prop, param);
+
+ param = icalparameter_new_encoding (ICAL_ENCODING_BASE64);
+ icalproperty_add_parameter (prop, param);
+
+ param = icalparameter_new_x (basename);
+ icalparameter_set_xname (param, X_E_CALDAV_ATTACHMENT_NAME);
+ icalproperty_add_parameter (prop, param);
+
+ icalcomponent_add_property (icalcomp, prop);
+ } else {
+ g_warning ("%s\n", error->message);
+ g_clear_error (&error);
+ }
+ g_free (basename);
+ g_object_unref (file);
+ }
+ icalcomponent_free (cclone);
+}
+
+static void
+convert_to_url_attachment (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp)
+{
+ ECalBackendCalDAVPrivate *priv;
+ GSList *to_remove = NULL;
+ icalcomponent *cclone;
+ icalproperty *p;
+
+ g_return_if_fail (cbdav != NULL);
+ g_return_if_fail (icalcomp != NULL);
+
+ cclone = icalcomponent_new_clone (icalcomp);
+
+ /* Remove all inline attachments first */
+ for (p = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
+ p;
+ p = icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY)) {
+ icalattach *attach;
+
+ attach = icalproperty_get_attach ((const icalproperty *)p);
+ if (!icalattach_get_is_url (attach))
+ to_remove = g_slist_prepend (to_remove, p);
+ }
+ g_slist_foreach (to_remove, remove_property, icalcomp);
+ g_slist_free (to_remove);
+
+ /* convert inline attachments to url attachments now */
+ priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+ for (p = icalcomponent_get_first_property (cclone, ICAL_ATTACH_PROPERTY);
+ p;
+ p = icalcomponent_get_next_property (cclone, ICAL_ATTACH_PROPERTY)) {
+ icalattach *attach;
+ gchar *dir;
+
+ attach = icalproperty_get_attach ((const icalproperty *)p);
+ if (icalattach_get_is_url (attach))
+ continue;
+
+ dir = g_build_filename (priv->local_attachments_store,
+ icalcomponent_get_uid (icalcomp),
+ NULL);
+ if (g_mkdir_with_parents (dir, 0700) >= 0) {
+ GError *error = NULL;
+ gchar *basename;
+ gchar *dest;
+ gchar *content;
+ gsize len;
+ gchar *decoded;
+
+ basename = icalproperty_get_parameter_as_string_r (p,
+ X_E_CALDAV_ATTACHMENT_NAME);
+ dest = g_build_filename (dir, basename, NULL);
+ g_free (basename);
+
+ content = (gchar *)icalattach_get_data (attach);
+ decoded = (gchar *)g_base64_decode (content, &len);
+ if (g_file_set_contents (dest, decoded, len, &error) == TRUE) {
+ icalproperty *prop;
+ gchar *url;
+
+ url = g_filename_to_uri (dest, NULL, NULL);
+ attach = icalattach_new_from_url (url);
+ prop = icalproperty_new_attach (attach);
+ icalattach_unref (attach);
+ icalcomponent_add_property (icalcomp, prop);
+ g_free (url);
+ } else {
+ g_warning ("%s\n", error->message);
+ g_clear_error (&error);
+ }
+ g_free (decoded);
+ g_free (dest);
+ }
+ g_free (dir);
+ }
+ icalcomponent_free (cclone);
+}
+
+static void
+remove_dir (const char *dir)
+{
+ GDir *d;
+
+ /*
+ * remove all files in the direcory first
+ * and call rmdir to remove the empty directory
+ * because ZFS does not support unlinking a directory.
+ */
+ d = g_dir_open (dir, 0, NULL);
+ if (d) {
+ const gchar *entry;
+
+ while ((entry = g_dir_read_name (d)) != NULL) {
+ gchar *path;
+ int ret;
+
+ path = g_build_filename (dir, entry, NULL);
+ if (g_file_test (path, G_FILE_TEST_IS_DIR))
+ remove_dir (path);
+ else
+ ret = g_unlink (path);
+ g_free (path);
+ }
+ g_dir_close (d);
+ }
+ g_rmdir (dir);
+}
+
+static void
+remove_cached_attachment (ECalBackendCalDAV *cbdav, const gchar *uid)
+{
+ ECalBackendCalDAVPrivate *priv;
+ GSList *l;
+ guint len;
+ gchar *dir;
+
+ g_return_if_fail (cbdav != NULL);
+ g_return_if_fail (uid != NULL);
+
+ priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+ l = e_cal_backend_cache_get_components_by_uid (priv->cache, uid);
+ len = g_slist_length (l);
+ g_slist_free (l);
+ if (len > 0)
+ return;
+
+ dir = g_build_filename (priv->local_attachments_store,
+ uid, NULL);
+ remove_dir (dir);
+ g_free (dir);
+}
+
/* callback for icalcomponent_foreach_tzid */
typedef struct {
ECalBackendCache *cache;
@@ -2642,6 +2896,7 @@ pack_cobj (ECalBackendCalDAV *cbdav, icalcomponent *icomp)
cclone = icalcomponent_new_clone (icomp);
strip_x_evolution_caldav (cclone);
+ convert_to_inline_attachment (cbdav, cclone);
icalcomponent_add_component (calcomp, cclone);
add_timezones_from_component (cbdav, calcomp, cclone);
} else {
@@ -2653,6 +2908,7 @@ pack_cobj (ECalBackendCalDAV *cbdav, icalcomponent *icomp)
subcomp;
subcomp = icalcomponent_get_next_component (calcomp, my_kind)) {
strip_x_evolution_caldav (subcomp);
+ convert_to_inline_attachment (cbdav, subcomp);
add_timezones_from_component (cbdav, calcomp, subcomp);
}
}
@@ -3201,6 +3457,7 @@ do_remove_object (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar *rid,
else
ecalcomp_set_synch_state (cache_comp_master, ECALCOMP_LOCALLY_DELETED);*/
}
+ remove_cached_attachment (cbdav, uid);
icalcomponent_free (cache_comp);
g_free (href);
@@ -4177,6 +4434,11 @@ e_cal_backend_caldav_dispose (GObject *object)
g_free (priv->uri);
g_free (priv->schedule_outbox_url);
+ if (priv->local_attachments_store) {
+ g_free (priv->local_attachments_store);
+ priv->local_attachments_store = NULL;
+ }
+
if (priv->cache != NULL) {
g_object_unref (priv->cache);
}
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index 15bf036..9a4ef12 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -1405,6 +1405,14 @@ set_local_attachment_store (ECal *ecal)
priv->local_attachment_store =
g_filename_to_uri (filename, NULL, NULL);
g_free (filename);
+ } else if (g_str_has_prefix (priv->uri, "caldav://")) {
+ gchar *filename = g_build_filename (g_get_home_dir (),
+ ".evolution/cache/calendar",
+ mangled_uri,
+ NULL);
+ priv->local_attachment_store =
+ g_filename_to_uri (filename, NULL, NULL);
+ g_free (filename);
}
g_free (mangled_uri);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]