diff options
Diffstat (limited to 'shell/e-local-storage.c')
-rw-r--r-- | shell/e-local-storage.c | 277 |
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; } |