diff options
-rw-r--r-- | mail/em-utils.c | 239 | ||||
-rw-r--r-- | mail/em-utils.h | 3 | ||||
-rw-r--r-- | plugins/itip-formatter/itip-formatter.c | 42 | ||||
-rw-r--r-- | plugins/mail-to-task/mail-to-task.c | 161 |
4 files changed, 147 insertions, 298 deletions
diff --git a/mail/em-utils.c b/mail/em-utils.c index 0e9742d8ab..0eab5f6fac 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -345,245 +345,6 @@ em_filename_make_safe (gchar *string) /* Saving messages... */ -static const gchar * -emu_save_get_filename_for_part (CamelMimePart *part) -{ - const gchar *filename; - - filename = camel_mime_part_get_filename (part); - if (filename == NULL) { - if (CAMEL_IS_MIME_MESSAGE (part)) { - filename = camel_mime_message_get_subject ( - CAMEL_MIME_MESSAGE (part)); - if (filename == NULL) - filename = _("message"); - } else - filename = _("attachment"); - } - - return filename; -} - -/** - * em_utils_save_part: - * @parent: parent window - * @prompt: prompt string - * @part: part to save - * - * Saves a mime part to disk (prompting the user for filename). - **/ -void -em_utils_save_part (GtkWindow *parent, const gchar *prompt, CamelMimePart *part) -{ - GtkWidget *file_chooser; - const gchar *utf8_filename; - gchar *uri = NULL, *filename; - - g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent)); - - utf8_filename = emu_save_get_filename_for_part (part); - filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL); - em_filename_make_safe (filename); - - file_chooser = e_file_get_save_filesel ( - parent, prompt, filename, GTK_FILE_CHOOSER_ACTION_SAVE); - - if (gtk_dialog_run (GTK_DIALOG (file_chooser)) != GTK_RESPONSE_OK) - goto exit; - - uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (file_chooser)); - - /* XXX Would be nice to mention _why_ we can't save. */ - if (!e_file_can_save (GTK_WINDOW (file_chooser), uri)) { - g_warning ("Unable to save %s", uri); - goto exit; - } - - e_file_update_save_path ( - gtk_file_chooser_get_current_folder_uri ( - GTK_FILE_CHOOSER (file_chooser)), TRUE); - - mail_save_part (part, uri, NULL, NULL, FALSE); - -exit: - gtk_widget_destroy (file_chooser); - g_free (uri); - g_free (filename); -} - -/* It "assigns" to each part its unique file name, based on the appearance. - parts contains CamelMimePart, returned value contains gchar *, in same - order as parts; resulting list should free data and GSList itself as well. -*/ -static GSList * -get_unique_file_names (GSList *parts) -{ - GSList *iter; - GSList *file_names = NULL; - - if (!parts) - return NULL; - - for (iter = parts; iter != NULL; iter = iter->next) { - CamelMimePart *part = iter->data; - const gchar *utf8_filename; - gchar *filename; - - utf8_filename = emu_save_get_filename_for_part (part); - filename = g_filename_from_utf8 (utf8_filename, -1, NULL, NULL, NULL); - em_filename_make_safe (filename); - - file_names = g_slist_prepend (file_names, filename); - } - - if (file_names) { - GSList *sorted_file_names; - gint counter = 1; - const gchar *last; - GCompareFunc cmp_func = (GCompareFunc) strcmp; - - #ifdef G_OS_WIN32 - cmp_func = (GCompareFunc) g_ascii_strcasecmp; - #endif - - /* we prepended, so reverse to make right order */ - file_names = g_slist_reverse (file_names); - - sorted_file_names = g_slist_sort (g_slist_copy (file_names), cmp_func); - last = sorted_file_names->data; - for (iter = sorted_file_names->next; iter; iter = iter->next) { - gchar *name = iter->data; - - if (name && last && cmp_func (name, last) == 0) { - gchar *new_name; - gchar *p = strrchr (name, '.'); - GSList *i2; - - /* if we have an extension, then place number before it (at p is ".ext"), - otherwise just append number in brackets */ - if (p) - new_name = g_strdup_printf ("%.*s(%d)%s", (gint) (p - name), name, counter, p); - else - new_name = g_strdup_printf ("%s(%d)", name, counter); - - /* we need to find the proper item in unsorted list and replace with new name; - we should always find that item, so no check for leaks */ - for (i2 = file_names; i2; i2 = i2->next) { - if (i2->data == name) { - g_free (name); - i2->data = new_name; - break; - } - } - - counter++; - } else { - last = name; - counter = 1; - } - } - - g_slist_free (sorted_file_names); - } - - return file_names; -} - -void -em_utils_save_parts (GtkWindow *parent, const gchar *prompt, GSList *parts) -{ - GtkWidget *file_chooser; - gchar *path_uri; - GSList *iter, *file_names, *iter_file; - - g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent)); - - file_chooser = e_file_get_save_filesel ( - parent, prompt, NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); - - if (gtk_dialog_run (GTK_DIALOG (file_chooser)) != GTK_RESPONSE_OK) - goto exit; - - path_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (file_chooser)); - - e_file_update_save_path (path_uri, FALSE); - - file_names = get_unique_file_names (parts); - - for (iter = parts, iter_file = file_names; iter && iter_file; iter = iter->next, iter_file = iter_file->next) { - CamelMimePart *part = iter->data; - gchar *uri, *filename; - - filename = iter_file->data; - uri = g_build_path ("/", path_uri, filename, NULL); - g_free (filename); - iter_file->data = NULL; - - /* XXX Would be nice to mention _why_ we can't save. */ - if (e_file_can_save (GTK_WINDOW (file_chooser), uri)) - mail_save_part (part, uri, NULL, NULL, FALSE); - else - g_warning ("Unable to save %s", uri); - - g_free (uri); - } - - g_slist_free (file_names); - g_free (path_uri); - -exit: - gtk_widget_destroy (file_chooser); -} - -/** - * em_utils_save_part_to_file: - * @parent: parent window - * @filename: filename to save to - * @part: part to save - * - * Save a part's content to a specific file - * Creates all needed directories and overwrites without prompting - * - * Returns %TRUE if saving succeeded, %FALSE otherwise - **/ -gboolean -em_utils_save_part_to_file(GtkWindow *parent, const gchar *filename, CamelMimePart *part) -{ - gint done; - gchar *dirname; - struct stat st; - - if (filename[0] == 0) - return FALSE; - - dirname = g_path_get_dirname(filename); - if (g_mkdir_with_parents(dirname, 0777) == -1) { - GtkWidget *w = e_error_new(parent, "mail:no-create-path", filename, g_strerror(errno), NULL); - g_free(dirname); - em_utils_show_error_silent (w); - return FALSE; - } - g_free(dirname); - - if (g_access(filename, F_OK) == 0) { - if (g_access(filename, W_OK) != 0) { - e_error_run(parent, E_ERROR_ASK_FILE_EXISTS_OVERWRITE, filename, NULL); - return FALSE; - } - } - - if (g_stat(filename, &st) != -1 && !S_ISREG(st.st_mode)) { - GtkWidget *w = e_error_new(parent, "mail:no-write-path-notfile", filename, NULL); - em_utils_show_error_silent (w); - return FALSE; - } - - /* FIXME: This doesn't handle default charsets */ - mail_msg_wait(mail_save_part(part, filename, emu_save_part_done, &done, FALSE)); - - return done; -} - struct _save_messages_data { CamelFolder *folder; GPtrArray *uids; diff --git a/mail/em-utils.h b/mail/em-utils.h index 79caba050e..9bb35b1dc2 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -52,8 +52,6 @@ void em_utils_edit_filters (GtkWidget *parent); void em_filename_make_safe (gchar *string); void em_utils_edit_vfolders (GtkWidget *parent); -void em_utils_save_part(GtkWindow *parent, const gchar *prompt, CamelMimePart *part); -gboolean em_utils_save_part_to_file(GtkWindow *parent, const gchar *filename, CamelMimePart *part); void em_utils_save_messages (GtkWindow *parent, CamelFolder *folder, GPtrArray *uids); void em_utils_flag_for_followup (EMailReader *reader, CamelFolder *folder, GPtrArray *uids); @@ -72,7 +70,6 @@ void em_utils_selection_set_urilist(GtkSelectionData *data, CamelFolder *folder, void em_utils_selection_get_urilist(GtkSelectionData *data, CamelFolder *folder); gchar *em_utils_temp_save_part(GtkWidget *parent, CamelMimePart *part, gboolean mode); -void em_utils_save_parts (GtkWindow *parent, const gchar *prompt, GSList * parts); gboolean em_utils_folder_is_drafts(CamelFolder *folder, const gchar *uri); gboolean em_utils_folder_is_templates(CamelFolder *folder, const gchar *uri); diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c index 8ed7a51b37..658acc07dc 100644 --- a/plugins/itip-formatter/itip-formatter.c +++ b/plugins/itip-formatter/itip-formatter.c @@ -57,7 +57,9 @@ #include <calendar/gui/itip-utils.h> #include <calendar/common/authentication.h> #include <shell/e-shell.h> +#include <shell/e-shell-utils.h> #include "itip-view.h" +#include <misc/e-attachment.h> #define CLASSID "itip://" #define GCONF_KEY_DELETE "/apps/evolution/itip/delete_processed" @@ -1474,18 +1476,54 @@ get_next (icalcompiter *iter) } static void +attachment_load_finish (EAttachment *attachment, + GAsyncResult *result, + GFile *file) +{ + EShell *shell; + GtkWindow *parent; + + /* XXX Theoretically, this should never fail. */ + e_attachment_load_finish (attachment, result, NULL); + + shell = e_shell_get_default (); + parent = e_shell_get_active_window (shell); + + e_attachment_save_async ( + attachment, file, (GAsyncReadyCallback) + e_attachment_save_handle_error, parent); + + g_object_unref (file); +} + +static void save_vcalendar_cb (GtkWidget *button, struct _itip_puri *pitip) { + EAttachment *attachment; + EShell *shell; + GFile *file; + g_return_if_fail (pitip != NULL); g_return_if_fail (pitip->vcalendar != NULL); g_return_if_fail (pitip->part != NULL); + shell = e_shell_get_default (); + file = e_shell_run_save_dialog ( + shell, _("Save Calendar"), NULL, NULL); + if (file == NULL) + return; + if (!camel_mime_part_get_filename (pitip->part)) { - /* To Translators: This is a default file name when saving calendar part */ + /* Translators: This is a default filename for a calendar. */ camel_mime_part_set_filename (pitip->part, _("calendar.ics")); } - em_utils_save_part (GTK_WINDOW (gtk_widget_get_toplevel (button)), _("Save calendar"), pitip->part); + attachment = e_attachment_new (); + e_attachment_set_mime_part (attachment, pitip->part); + + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + attachment_load_finish, file); } static GtkWidget * diff --git a/plugins/mail-to-task/mail-to-task.c b/plugins/mail-to-task/mail-to-task.c index 1c8be4538a..5c373d86c1 100644 --- a/plugins/mail-to-task/mail-to-task.c +++ b/plugins/mail-to-task/mail-to-task.c @@ -57,6 +57,7 @@ #include <shell/e-shell-view.h> #include <shell/e-shell-window-actions.h> #include <calendar/gui/cal-editor-utils.h> +#include <misc/e-attachment-store.h> #define E_SHELL_WINDOW_ACTION_CONVERT_TO_EVENT(window) \ E_SHELL_WINDOW_ACTION ((window), "mail-convert-to-event") @@ -72,26 +73,6 @@ gboolean mail_browser_init (GtkUIManager *ui_manager, gboolean mail_shell_view_init (GtkUIManager *ui_manager, EShellView *shell_view); -static gchar * -clean_name(const guchar *s) -{ - GString *out = g_string_new(""); - guint32 c; - gchar *r; - - while ((c = camel_utf8_getc ((const guchar **)&s))) - { - if (!g_unichar_isprint (c) || ( c < 0x7f && strchr (" /'\"`&();|<>$%{}!", c ))) - c = '_'; - g_string_append_u (out, c); - } - - r = g_strdup (out->str); - g_string_free (out, TRUE); - - return r; -} - static void set_attendees (ECalComponent *comp, CamelMimeMessage *message, const gchar *organizer) { @@ -281,61 +262,133 @@ set_organizer (ECalComponent *comp) } static void +attachment_load_finished (EAttachment *attachment, + GAsyncResult *result, + gpointer user_data) +{ + struct { + gchar **uris; + gboolean done; + } *status = user_data; + + /* XXX Should be no need to check for error here. + * This is just to reset state in the EAttachment. */ + e_attachment_load_finish (attachment, result, NULL); + + status->done = TRUE; +} + +static void +attachment_save_finished (EAttachmentStore *store, + GAsyncResult *result, + gpointer user_data) +{ + gchar **uris; + + struct { + gchar **uris; + gboolean done; + } *status = user_data; + + /* XXX Add some error handling here! */ + uris = e_attachment_store_save_finish (store, result, NULL); + + status->uris = uris; + status->done = TRUE; +} + +static void set_attachments (ECal *client, ECalComponent *comp, CamelMimeMessage *message) { - gint parts, i; - GSList *list = NULL; - const gchar *uid; - const gchar *store_uri; - gchar *store_dir; + /* XXX Much of this is copied from CompEditor::get_attachment_list(). + * Perhaps it should be split off as a separate utility? */ + + EAttachmentStore *store; CamelDataWrapper *content; + CamelMultipart *multipart; + GFile *destination; + GSList *list = NULL; + const gchar *comp_uid = NULL; + const gchar *local_store; + gint ii, n_parts; + gchar *uri; + + struct { + gchar **uris; + gboolean done; + } status; content = camel_medium_get_content_object ((CamelMedium *) message); if (!content || !CAMEL_IS_MULTIPART (content)) return; - parts = camel_multipart_get_number (CAMEL_MULTIPART (content)); - if (parts < 1) + n_parts = camel_multipart_get_number (CAMEL_MULTIPART (content)); + if (n_parts < 1) return; - e_cal_component_get_uid (comp, &uid); - store_uri = e_cal_get_local_attachment_store (client); - if (!store_uri) - return; - store_dir = g_filename_from_uri (store_uri, NULL, NULL); + e_cal_component_get_uid (comp, &comp_uid); + local_store = e_cal_get_local_attachment_store (client); + uri = g_build_path ("/", local_store, comp_uid, NULL); + destination = g_file_new_for_uri (uri); + g_free (uri); + + /* Create EAttachments from the MIME parts and add them to the + * attachment store. */ - for (i = 1; i < parts; i++) - { - gchar *filename, *path, *tmp; - const gchar *orig_filename; + multipart = CAMEL_MULTIPART (content); + store = E_ATTACHMENT_STORE (e_attachment_store_new ()); + + for (ii = 1; ii < n_parts; ii++) { CamelMimePart *mime_part; + EAttachment *attachment; - mime_part = camel_multipart_get_part (CAMEL_MULTIPART (content), i); + status.done = FALSE; - orig_filename = camel_mime_part_get_filename (mime_part); - if (!orig_filename) - continue; + attachment = e_attachment_new (); + mime_part = camel_multipart_get_part (multipart, ii); + e_attachment_set_mime_part (attachment, mime_part); - tmp = clean_name ((const guchar *)orig_filename); - filename = g_strdup_printf ("%s-%s", uid, tmp); - path = g_build_filename (store_dir, filename, NULL); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + attachment_load_finished, &status); - if (em_utils_save_part_to_file (NULL, path, mime_part)) - { - gchar *uri; - uri = g_filename_to_uri (path, NULL, NULL); - list = g_slist_append (list, g_strdup (uri)); - g_free (uri); - } + /* Loading should be instantaneous since we already have + * the full content, but we still have to crank the main + * loop until the callback gets triggered. */ + while (!status.done) + gtk_main_iteration (); - g_free (tmp); - g_free (filename); - g_free (path); + e_attachment_store_add_attachment (store, attachment); + g_object_unref (attachment); } - g_free (store_dir); + status.uris = NULL; + status.done = FALSE; + + e_attachment_store_save_async ( + store, destination, (GAsyncReadyCallback) + attachment_save_finished, &status); + + /* We can't return until we have results, so crank + * the main loop until the callback gets triggered. */ + while (!status.done) + gtk_main_iteration (); + + g_return_if_fail (status.uris != NULL); + /* Transfer the URI strings to the GSList. */ + for (ii = 0; status.uris[ii] != NULL; ii++) { + list = g_slist_prepend (list, status.uris[ii]); + status.uris[ii] = NULL; + } + + g_free (status.uris); + + /* XXX Does this take ownership of the list? */ e_cal_component_set_attachment_list (comp, list); + + g_object_unref (destination); + g_object_unref (store); } static void |