* Authors :
* JP Rosevear <jpr@ximian.com>
* Rodrigo Moya <rodrigo@ximian.com>
- *
- * Copyright 2003, Novell, Inc.
+ * Harish Krishnaswamy <kharish@novell.com>
+ * Copyright 2003, Novell, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* USA
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include <e-gw-connection.h>
#include <e-gw-message.h>
#include <libecal/e-cal-recur.h>
#include <libecal/e-cal-time-util.h>
+#include <libsoup/soup-misc.h>
#include "e-cal-backend-groupwise-utils.h"
#include <libedataserver/e-source-list.h>
}
+static void
+e_cal_backend_groupwise_set_attachments_from_comp (ECalComponent *comp,
+ EGwItem *item)
+{
+ GSList *attach_list = NULL, *attach_file_list = NULL;
+ GSList *l;
+
+ e_cal_component_get_attachment_list (comp, &attach_file_list);
+
+ for (l = attach_file_list; l ; l = l->next) {
+
+ EGwItemAttachment *attach_item;
+ char *file_contents, *encoded_data;
+ int fd, len;
+ int len_read = 0;
+ char buf[1024];
+ struct stat sb;
+ char *attach_filename_full, *filename;
+ const char *uid;
+
+
+ attach_filename_full = (char *)l->data + 7;
+ attach_item = g_new0 (EGwItemAttachment, 1);
+ /* FIXME the member does not follow the naming convention.
+ * Should be fixed in e-gw-item*/
+ attach_item->contentType = g_strdup (gnome_vfs_get_mime_type (attach_filename_full));
+
+ /*
+ * Would gnome_vfs_async be better suited for this ?
+ */
+ fd = open (attach_filename_full, O_RDONLY);
+ if (fd == -1) {
+ /* TODO handle error conditions */
+ g_free (attach_item);
+ g_message ("DEBUG: could not open the file descriptor\n");
+ }
+ if (fstat (fd, &sb) == -1) {
+ /* TODO handle error conditions */
+ g_free (attach_item);
+ g_message ("DEBUG: could not fstat the attachment file\n");
+ continue;
+ }
+ len = sb.st_size;
+
+ file_contents = g_malloc (len + 1);
+
+ while (len_read < len) {
+ int c = read (fd, buf, sizeof (buf));
+
+ if (c == -1)
+ break;
+
+ memcpy (&file_contents[len_read], buf, c);
+ len_read += c;
+ }
+ file_contents [len_read] = 0;
+
+ /* Extract the simple file name from the
+ * attach_filename_full which is of the form
+ * file://<path>/compuid-<simple filename>
+ */
+ e_cal_component_get_uid (comp, &uid);
+ filename = g_strrstr (attach_filename_full, uid);
+
+ if (filename == NULL) {
+ /* TODO handle error conditions */
+ g_free (attach_item);
+ g_message ("DEBUG:\n This is an invalid attachment file\n");
+ continue;
+ }
+
+
+ attach_item->name = g_strdup (filename + strlen(uid) + 1);
+ /* do a base64 encoding so it can be embedded in a soap
+ * message */
+ /* TODO handle error conditions */
+ encoded_data = soup_base64_encode (file_contents, len_read);
+ attach_item->data = encoded_data;
+ attach_item->size = strlen (encoded_data);
+
+ g_free (file_contents);
+ close (fd);
+ attach_list = g_slist_append (attach_list, attach_item);
+ }
+
+ e_gw_item_set_attach_id_list (item, attach_list);
+}
+
static EGwItem *
set_properties_from_cal_component (EGwItem *item, ECalComponent *comp, ECalBackendGroupwise *cbgw)
{
e_gw_item_set_recurrence_dates (item, recur_dates);
}
+
+ /* attachments */
+ if (e_cal_component_has_attachments (comp)) {
+ e_cal_backend_groupwise_set_attachments_from_comp (comp, item);
+ }
return item;
}
return set_properties_from_cal_component (item, comp, cbgw);
}
+/* Fetch data from the server and unencode it to the actual data
+ * and populate the attach_data
+ */
+static gboolean
+get_attach_data_from_server (GSList *attach_item_list, ECalBackendGroupwise *cbgw)
+{
+ GSList *l;
+ EGwConnection *cnc;
+ EGwConnectionStatus status;
+
+ cnc = e_cal_backend_groupwise_get_connection (cbgw);
+ g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
+
+ for (l = attach_item_list; l; l = l->next) {
+ EGwItemAttachment *attach_item = (EGwItemAttachment *) l->data;
+
+ status = e_gw_connection_get_attachment (cnc, attach_item->id, 0, -1,
+ (const char *)&(attach_item->data), &(attach_item->size));
+
+ if (status != E_GW_CONNECTION_STATUS_OK ) {
+ g_warning ("Failed to read the attachment from the server\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void
+set_attachments_to_cal_component (EGwItem *item, ECalComponent *comp, ECalBackendGroupwise *cbgw)
+{
+ /*TODO if attach_list just has attach_ids - fetch the
+ * attachments. For each, serialize them in the attach
+ * store location and set the url in the cal component*/
+ GSList *attach_data = NULL, *attach_id_list, *l;
+ GSList *comp_attachment_list = NULL;
+
+
+ attach_id_list = e_gw_item_get_attach_id_list (item);
+ if (attach_id_list == NULL)
+ return;
+
+ /* Download the data and populate the structure */
+ if (!get_attach_data_from_server (attach_id_list, cbgw))
+ return;
+
+
+ /* FIXME the code below assumes the attach_data now contains
+ * EGwItemAttachment structures and proceeds to serialize
+ * them. Check base64 encoding assumptions by mailer code*/
+
+ for (l = attach_data; l ; l = l->next) {
+ int fd, length;
+ char *attach_file_url, *attach_data;
+ const char *uid;
+ EGwItemAttachment *attach_item;
+
+ attach_item = (EGwItemAttachment *) l->data;
+ /*TODO decode the encoded data on attachments */
+ if (attach_item->size > 0) {
+ attach_data = soup_base64_decode (attach_item->data, &length);
+ }
+ e_cal_component_get_uid (comp, &uid);
+ attach_file_url = g_strconcat
+ (e_cal_backend_groupwise_get_local_attachments_store (cbgw),
+ "/", uid, "-", attach_item->name, NULL);
+ fd = open (attach_file_url+7, O_RDWR|O_CREAT|O_TRUNC, 0600);
+ if (fd == -1) {
+ /* TODO handle error conditions */
+ g_message ("DEBUG: could not serialize attachments\n");
+ }
+
+ if (write (fd, attach_data, length) == -1) {
+ /* TODO handle error condition */
+ g_message ("DEBUG: attachment write failed.\n");
+ }
+
+ g_free (attach_data);
+ close (fd);
+
+ comp_attachment_list = g_slist_append
+ (comp_attachment_list, attach_file_url);
+ }
+
+}
ECalComponent *
e_gw_item_to_cal_component (EGwItem *item, ECalBackendGroupwise *cbgw)
{
GSList *recipient_list, *rl, *attendee_list = NULL;
EGwItemOrganizer *organizer;
EGwItemType item_type;
+ GSList *attach_list;
default_zone = e_cal_backend_groupwise_get_default_zone (cbgw);
categories_by_id = e_cal_backend_groupwise_get_categories_by_id (cbgw);
e_cal_component_set_organizer (comp, cal_organizer);
}
+ /* set attachments */
+ attach_list = e_gw_item_get_attach_id_list (item);
+ if (attach_list != NULL) {
+ /* Iterate thro the list and stuff it into ical*/
+ EGwItemAttachment *attach_data;
+ int attach_length;
+ unsigned char *attachment;
+ EGwConnectionStatus status;
+
+ /* First check if the item has attachments . if yes check if it
+ * exists on the filesystem or pull it from the server,
+ * serialize it.
+ */
+ /* nice if we could just get it from the cache/item not
+ * from a n/w call here */
+ attach_data = (EGwItemAttachment *) attach_list->data;
+ status = e_gw_connection_get_attachment (e_cal_backend_groupwise_get_connection (cbgw), attach_data->id, 0, 0,
+ (const char *)&attachment, &attach_length);
+ if (status == E_GW_CONNECTION_STATUS_OK)
+ g_message ("DEBUG : Spewing out the attachment\n%s\n", attachment);
+ else
+ g_message ("DEBUG:attachment call was a disaster\n");
+
+ set_attachments_to_cal_component (item, comp, cbgw);
+
+ }
+
/* set specific properties */
switch (item_type) {
case E_GW_ITEM_TYPE_APPOINTMENT :
return NULL;
}
+ e_cal_component_commit_sequence (comp);
+ g_message ("DEBUG:\n %s\n", e_cal_component_get_as_string (comp));
+
return comp;
}
void
e_cal_backend_groupwise_store_settings (EGwSendOptions *opts, ECalBackendGroupwise *cbgw)
{
- ECalBackendGroupwisePrivate *priv = cbgw->priv;
EGwSendOptionsGeneral *gopts;
EGwSendOptionsStatusTracking *sopts;
icaltimetype tt;
g_object_unref (gconf);
}
+
+
+
/* fields for storing info while offline */
char *user_email;
+ char *local_attachments_store;
};
static void e_cal_backend_groupwise_dispose (GObject *object);
g_mutex_unlock (mutex);
return status;
}
- status = e_gw_connection_create_cursor (priv->cnc, priv->container_id, "recipients message recipientStatus default", NULL, &cursor);
+ status = e_gw_connection_create_cursor (priv->cnc,
+ priv->container_id,
+ "recipients message recipientStatus attachments default", NULL, &cursor);
if (status != E_GW_CONNECTION_STATUS_OK) {
e_cal_backend_groupwise_notify_error_code (cbgw, status);
g_mutex_unlock (mutex);
priv->user_email = NULL;
}
+ if (priv->local_attachments_store) {
+ g_free (priv->local_attachments_store);
+ priv->local_attachments_store = NULL;
+ }
+
if (priv->timeout_id) {
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
ECalBackendGroupwise *cbgw;
ECalBackendGroupwisePrivate *priv;
ECalBackendSyncStatus status;
+ char *mangled_uri;
+ int i;
cbgw = E_CAL_BACKEND_GROUPWISE (backend);
priv = cbgw->priv;
priv->username = g_strdup (username);
priv->password = g_strdup (password);
-
+
+ /* Set the local attachment store*/
+ mangled_uri = g_strdup (e_cal_backend_get_uri (E_CAL_BACKEND (cbgw)));
+ /* mangle the URI to not contain invalid characters */
+ for (i = 0; i < strlen (mangled_uri); i++) {
+ switch (mangled_uri[i]) {
+ case ':' :
+ case '/' :
+ mangled_uri[i] = '_';
+ }
+ }
+
+ priv->local_attachments_store =
+ g_strconcat ("file://", g_get_home_dir (), "/", ".evolution/cache/calendar",
+ "/", mangled_uri, NULL);
+ g_free (mangled_uri);
+
/* FIXME: no need to set it online here when we implement the online/offline stuff correctly */
status = connect_to_server (cbgw);
cbgw->priv = priv;
}
-/* Class initialization function for the file backend */
+/* Class initialization function for the gw backend */
static void
e_cal_backend_groupwise_class_init (ECalBackendGroupwiseClass *class)
{
if (msg)
e_cal_backend_notify_error (E_CAL_BACKEND (cbgw), msg);
}
+
+const char *
+e_cal_backend_groupwise_get_local_attachments_store (ECalBackendGroupwise *cbgw)
+{
+ g_return_val_if_fail (E_IS_CAL_BACKEND_GROUPWISE (cbgw), NULL);
+ return cbgw->priv->local_attachments_store;
+}
/* The component listener to keep track of the lifetime of backends */
EComponentListener *comp_listener;
+
+ char *local_attachment_store;
};
\f
priv->load_state = E_CAL_LOAD_NOT_LOADED;
priv->uri = NULL;
+ priv->local_attachment_store = NULL;
priv->mutex = g_mutex_new ();
priv->listener = e_cal_listener_new (cal_set_mode_cb, ecal);
priv->uri = NULL;
}
+ if (priv->local_attachment_store) {
+ g_free (priv->local_attachment_store);
+ priv->local_attachment_store = NULL;
+ }
+
if (priv->mutex) {
g_mutex_free (priv->mutex);
priv->mutex = NULL;
g_static_mutex_unlock (&e_cal_lock);
}
+
+/* TODO - For now, the policy of where each backend serializes its
+ * attachment data is hardcoded below. Should this end up as a
+ * gconf key set during the account creation and fetched
+ * from eds???
+ */
+static void
+set_local_attachment_store (ECal *ecal)
+{
+ ECalPrivate *priv;
+ char *mangled_uri;
+ int i;
+
+ priv = ecal->priv;
+ mangled_uri = g_strdup (priv->uri);
+ /* mangle the URI to not contain invalid characters */
+ for (i = 0; i < strlen (mangled_uri); i++) {
+ switch (mangled_uri[i]) {
+ case ':' :
+ case '/' :
+ mangled_uri[i] = '_';
+ }
+ }
+
+ /* the file backend uses its uri as the attachment store*/
+ if (g_str_has_prefix (priv->uri, "file://"))
+ priv->local_attachment_store = g_strdup (priv->uri);
+ if (g_str_has_prefix (priv->uri, "groupwise://")) {
+ /* points to the location of the cache*/
+ priv->local_attachment_store =
+ g_strconcat ("file://", g_get_home_dir (), "/", ".evolution/cache/calendar",
+ "/", mangled_uri, NULL);
+ }
+}
+
/**
* e_cal_new:
* @source:
return NULL;
}
+ /* Set the local attachment store path for the calendar */
+ set_local_attachment_store (ecal);
+
/* initialize component listener */
ecal->priv->comp_listener = e_component_listener_new ((Bonobo_Unknown) ecal->priv->cal);
g_signal_connect (G_OBJECT (ecal->priv->comp_listener), "component_died",
}
/**
+ * e_cal_get_local_attachment_store
+ * @ecal: A calendar ecal.
+ *
+ * Queries the URL where the calendar attachments are
+ * serialized in the local filesystem. This enable clients
+ * to operate with the reference to attachments rather than the data itself
+ * unless it specifically uses the attachments for open/sending
+ * operations.
+ * Return value: The URL where the attachments are serialized in the
+ * local filesystem.
+ **/
+const char *
+e_cal_get_local_attachment_store (ECal *ecal)
+{
+ ECalPrivate *priv;
+
+ g_return_val_if_fail (ecal != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL (ecal), NULL);
+
+ priv = ecal->priv;
+ return (const char *)priv->local_attachment_store;
+}
+
+/**
* e_cal_is_read_only:
* @ecal: A calendar ecal.
* @read_only: