aboutsummaryrefslogtreecommitdiffstats
path: root/shell/e-local-storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/e-local-storage.c')
-rw-r--r--shell/e-local-storage.c277
1 files changed, 243 insertions, 34 deletions
diff --git a/shell/e-local-storage.c b/shell/e-local-storage.c
index b97b25b8ec..05a142152e 100644
--- a/shell/e-local-storage.c
+++ b/shell/e-local-storage.c
@@ -25,6 +25,9 @@
*
* - If we have `.' or `..' as path elements, we lose.
*
+ * - If the LocalStorage is destroyed and an async operation on a shell component is
+ * pending, we get a callback on a bogus object. We need support for cancelling
+ * operations on the shell component.
*/
#ifdef HAVE_CONFIG_H
@@ -34,6 +37,7 @@
#define _POSIX_SOURCE /* Yuck. */
#include <dirent.h>
+#include <errno.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -54,18 +58,17 @@ static EStorageClass *parent_class = NULL;
#define SUBFOLDER_DIR_NAME_LEN 10
struct _ELocalStoragePrivate {
- EComponentRegistry *component_registry;
+ EFolderTypeRegistry *folder_type_registry;
char *base_path;
};
/* Utility functions. */
-#if 0
-/* Translate a storage path into a real path on the file system. */
+/* Translate a storage path into a physical path on the file system. */
static char *
-get_real_path (ELocalStorage *local_storage,
- const char *path)
+get_physical_path (ELocalStorage *local_storage,
+ const char *path)
{
EStorage *storage;
ELocalStoragePrivate *priv;
@@ -80,7 +83,7 @@ get_real_path (ELocalStorage *local_storage,
/* @path is always absolute, so it starts with a slash. The base class should
make sure this is the case; if not, it's broken. */
- g_assert (*path != G_DIR_SEPARATOR);
+ g_assert (*path == G_DIR_SEPARATOR);
path++;
/* Calculate the length of the real path. */
@@ -93,7 +96,7 @@ get_real_path (ELocalStorage *local_storage,
real_path_len++; /* For the separating slash. */
/* Take account for the fact that we need to translate every separator into
- `children/'. */
+ `subfolders/'. */
p = path;
while (1) {
newp = strchr (p, G_DIR_SEPARATOR);
@@ -121,8 +124,10 @@ get_real_path (ELocalStorage *local_storage,
p = path;
while (1) {
newp = strchr (p, G_DIR_SEPARATOR);
- if (newp == NULL)
+ if (newp == NULL) {
+ strcpy (dp, p);
break;
+ }
memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too. */
dp += newp - p + 1;
@@ -141,7 +146,6 @@ get_real_path (ELocalStorage *local_storage,
return real_path;
}
-#endif
static gboolean
load_folders (ELocalStorage *local_storage,
@@ -230,6 +234,127 @@ load_all_folders (ELocalStorage *local_storage)
return load_folders (local_storage, NULL, G_DIR_SEPARATOR_S, base_path);
}
+static EStorageResult
+errno_to_storage_result (void)
+{
+ EStorageResult storage_result;
+
+ switch (errno) {
+ case EACCES:
+ case EROFS:
+ storage_result = E_STORAGE_PERMISSIONDENIED;
+ break;
+ case EEXIST:
+ storage_result = E_STORAGE_EXISTS;
+ break;
+ case ENOSPC:
+ storage_result = E_STORAGE_NOSPACE;
+ break;
+ default:
+ storage_result = E_STORAGE_GENERICERROR;
+ }
+
+ return storage_result;
+}
+
+static EStorageResult
+shell_component_result_to_storage_result (EvolutionShellComponentResult result)
+{
+ /* FIXME: Maybe we need better mapping here. */
+ switch (result) {
+ case EVOLUTION_SHELL_COMPONENT_OK:
+ return E_STORAGE_OK;
+ case EVOLUTION_SHELL_COMPONENT_NOTFOUND:
+ return E_STORAGE_NOTFOUND;
+ case EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDTYPE:
+ return E_STORAGE_UNSUPPORTEDTYPE;
+ case EVOLUTION_SHELL_COMPONENT_UNSUPPORTEDOPERATION:
+ return E_STORAGE_UNSUPPORTEDOPERATION;
+ case EVOLUTION_SHELL_COMPONENT_EXISTS:
+ return E_STORAGE_EXISTS;
+ case EVOLUTION_SHELL_COMPONENT_PERMISSIONDENIED:
+ return E_STORAGE_PERMISSIONDENIED;
+ case EVOLUTION_SHELL_COMPONENT_ALREADYOWNED:
+ case EVOLUTION_SHELL_COMPONENT_BUSY:
+ case EVOLUTION_SHELL_COMPONENT_CORBAERROR:
+ case EVOLUTION_SHELL_COMPONENT_HASSUBFOLDERS:
+ case EVOLUTION_SHELL_COMPONENT_INTERNALERROR:
+ case EVOLUTION_SHELL_COMPONENT_INTERRUPTED:
+ case EVOLUTION_SHELL_COMPONENT_INVALIDARG:
+ case EVOLUTION_SHELL_COMPONENT_INVALIDURI:
+ case EVOLUTION_SHELL_COMPONENT_NOSPACE:
+ case EVOLUTION_SHELL_COMPONENT_NOTOWNED:
+ case EVOLUTION_SHELL_COMPONENT_UNKNOWNERROR:
+ default:
+ return E_STORAGE_GENERICERROR;
+ }
+}
+
+
+/* Callbacks for the async methods invoked on the `Evolution::ShellComponent's. */
+
+struct _AsyncCreateFolderCallbackData {
+ EStorage *storage;
+
+ char *parent_path;
+ char *name;
+ char *type;
+ char *description;
+ char *physical_uri;
+ char *physical_path;
+
+ EStorageResultCallback callback;
+ void *callback_data;
+};
+typedef struct _AsyncCreateFolderCallbackData AsyncCreateFolderCallbackData;
+
+static void
+component_async_create_folder_callback (EvolutionShellComponentClient *shell_component_client,
+ EvolutionShellComponentResult result,
+ void *data)
+{
+ AsyncCreateFolderCallbackData *callback_data;
+
+ callback_data = (AsyncCreateFolderCallbackData *) data;
+
+ if (result != EVOLUTION_SHELL_COMPONENT_OK) {
+ /* XXX: This assumes the component won't leave any files in the directory. */
+ rmdir (callback_data->physical_path);
+ } else {
+ EFolder *folder;
+
+ folder = e_local_folder_new (callback_data->name,
+ callback_data->type,
+ callback_data->description);
+
+ e_folder_set_physical_uri (folder, callback_data->physical_uri);
+
+ if (e_local_folder_save (E_LOCAL_FOLDER (folder))) {
+ e_storage_new_folder (callback_data->storage,
+ callback_data->parent_path,
+ folder);
+ } else {
+ rmdir (callback_data->physical_path);
+ gtk_object_unref (GTK_OBJECT (folder));
+ result = E_STORAGE_IOERROR;
+ }
+ }
+
+ bonobo_object_unref (BONOBO_OBJECT (shell_component_client));
+
+ (* callback_data->callback) (callback_data->storage,
+ shell_component_result_to_storage_result (result),
+ callback_data->callback_data);
+
+ g_free (callback_data->parent_path);
+ g_free (callback_data->name);
+ g_free (callback_data->type);
+ g_free (callback_data->description);
+ g_free (callback_data->physical_uri);
+ g_free (callback_data->physical_path);
+ g_free (callback_data);
+}
+
/* GtkObject methods. */
@@ -244,8 +369,8 @@ impl_destroy (GtkObject *object)
g_free (priv->base_path);
- if (priv->component_registry != NULL)
- gtk_object_unref (GTK_OBJECT (priv->component_registry));
+ if (priv->folder_type_registry != NULL)
+ gtk_object_unref (GTK_OBJECT (priv->folder_type_registry));
g_free (priv);
@@ -263,23 +388,107 @@ impl_get_name (EStorage *storage)
}
static void
-impl_create_folder (EStorage *storage,
- const char *path,
- const char *type,
- const char *description,
- EStorageResultCallback callback,
- void *data)
+impl_async_create_folder (EStorage *storage,
+ const char *path,
+ const char *type,
+ const char *description,
+ EStorageResultCallback callback,
+ void *data)
{
ELocalStorage *local_storage;
+ ELocalStoragePrivate *priv;
+ EvolutionShellComponentClient *component_client;
+ const char *folder_name;
+ AsyncCreateFolderCallbackData *callback_data;
+ char *physical_path;
+ char *physical_uri;
+ char *parent_path;
local_storage = E_LOCAL_STORAGE (storage);
+ priv = local_storage->priv;
+
+ component_client = e_folder_type_registry_get_handler_for_type (priv->folder_type_registry,
+ type);
+ if (component_client == NULL) {
+ (* callback) (storage, E_STORAGE_INVALIDTYPE, data);
+ return;
+ }
+
+ g_assert (g_path_is_absolute (path));
+
+ folder_name = g_basename (path);
+ if (folder_name == path + 1) {
+ /* We want a direct child of the root, so we don't need to create a
+ `subfolders' directory. */
+ physical_path = get_physical_path (local_storage, path);
+ parent_path = g_strdup (G_DIR_SEPARATOR_S);
+ } else {
+ char *parent_physical_path;
+ char *subfolders_directory_physical_path;
+
+ /* Create the `subfolders' subdirectory under the parent. */
+
+ parent_path = g_strndup (path, folder_name - path - 1);
+ parent_physical_path = get_physical_path (local_storage, parent_path);
+ subfolders_directory_physical_path = g_concat_dir_and_file (parent_physical_path,
+ SUBFOLDER_DIR_NAME);
+
+ if (! g_file_exists (subfolders_directory_physical_path)
+ && mkdir (subfolders_directory_physical_path, 0700) == -1) {
+ g_free (parent_path);
+ g_free (subfolders_directory_physical_path);
+ g_free (parent_physical_path);
+
+ (* callback) (storage, errno_to_storage_result (), data);
+ return;
+ }
+
+ physical_path = g_concat_dir_and_file (subfolders_directory_physical_path,
+ folder_name);
+ g_free (subfolders_directory_physical_path);
+ g_free (parent_physical_path);
+ }
+
+ /* Create the directory that holds the folder. */
+
+ if (mkdir (physical_path, 0700) == -1) {
+ g_free (physical_path);
+ (* callback) (storage, errno_to_storage_result (), data);
+ return;
+ }
+
+ /* Finally tell the component to do the job of creating the physical files in
+ it. */
+ /* FIXME: We should put the operations on a queue so that we can cancel them when
+ the ELocalStorage is destroyed. */
+
+ physical_uri = g_strconcat ("file://", physical_path, NULL);
+
+ callback_data = g_new (AsyncCreateFolderCallbackData, 1);
+ callback_data->storage = storage;
+ callback_data->parent_path = parent_path;
+ callback_data->name = g_strdup (folder_name);
+ callback_data->type = g_strdup (type);
+ callback_data->description = g_strdup (description);
+ callback_data->physical_uri = physical_uri;
+ callback_data->physical_path = physical_path;
+ callback_data->callback = callback;
+ callback_data->callback_data = data;
+
+ bonobo_object_ref (BONOBO_OBJECT (component_client));
+
+ evolution_shell_component_client_async_create_folder (component_client,
+ physical_path,
+ type,
+ component_async_create_folder_callback,
+ callback_data);
}
static void
-impl_remove_folder (EStorage *storage,
- const char *path,
- EStorageResultCallback callback,
- void *data)
+impl_async_remove_folder (EStorage *storage,
+ const char *path,
+ EStorageResultCallback callback,
+ void *data)
{
ELocalStorage *local_storage;
@@ -299,11 +508,11 @@ class_init (ELocalStorageClass *class)
object_class = GTK_OBJECT_CLASS (class);
storage_class = E_STORAGE_CLASS (class);
- object_class->destroy = impl_destroy;
+ object_class->destroy = impl_destroy;
- storage_class->get_name = impl_get_name;
- storage_class->create_folder = impl_create_folder;
- storage_class->remove_folder = impl_remove_folder;
+ storage_class->get_name = impl_get_name;
+ storage_class->async_create_folder = impl_async_create_folder;
+ storage_class->async_remove_folder = impl_async_remove_folder;
}
static void
@@ -314,7 +523,7 @@ init (ELocalStorage *local_storage)
priv = g_new (ELocalStoragePrivate, 1);
priv->base_path = NULL;
- priv->component_registry = NULL;
+ priv->folder_type_registry = NULL;
local_storage->priv = priv;
}
@@ -322,7 +531,7 @@ init (ELocalStorage *local_storage)
static gboolean
construct (ELocalStorage *local_storage,
- EComponentRegistry *component_registry,
+ EFolderTypeRegistry *folder_type_registry,
const char *base_path)
{
ELocalStoragePrivate *priv;
@@ -338,9 +547,9 @@ construct (ELocalStorage *local_storage,
g_return_val_if_fail (base_path_len != 0, FALSE);
- g_assert (priv->component_registry == NULL);
- gtk_object_ref (GTK_OBJECT (component_registry));
- priv->component_registry = component_registry;
+ g_assert (priv->folder_type_registry == NULL);
+ gtk_object_ref (GTK_OBJECT (folder_type_registry));
+ priv->folder_type_registry = folder_type_registry;
g_assert (priv->base_path == NULL);
priv->base_path = g_strndup (base_path, base_path_len);
@@ -349,18 +558,18 @@ construct (ELocalStorage *local_storage,
}
EStorage *
-e_local_storage_open (EComponentRegistry *component_registry,
+e_local_storage_open (EFolderTypeRegistry *folder_type_registry,
const char *base_path)
{
EStorage *new;
- g_return_val_if_fail (component_registry != NULL, NULL);
- g_return_val_if_fail (E_IS_COMPONENT_REGISTRY (component_registry), NULL);
+ g_return_val_if_fail (folder_type_registry != NULL, NULL);
+ g_return_val_if_fail (E_IS_FOLDER_TYPE_REGISTRY (folder_type_registry), NULL);
g_return_val_if_fail (base_path != NULL, NULL);
new = gtk_type_new (e_local_storage_get_type ());
- if (! construct (E_LOCAL_STORAGE (new), component_registry, base_path)) {
+ if (! construct (E_LOCAL_STORAGE (new), folder_type_registry, base_path)) {
gtk_object_unref (GTK_OBJECT (new));
return NULL;
}