Kill more redundant save functions.

This commit is contained in:
Matthew Barnes
2009-11-07 16:08:26 -05:00
parent 86ecfc5053
commit 5783bb4eb0
4 changed files with 147 additions and 298 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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"
@ -1473,19 +1475,55 @@ get_next (icalcompiter *iter)
return ret;
}
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 *

View File

@ -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)
{
@ -280,62 +261,134 @@ set_organizer (ECalComponent *comp)
return res;
}
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);
for (i = 1; i < parts; i++)
{
gchar *filename, *path, *tmp;
const gchar *orig_filename;
/* Create EAttachments from the MIME parts and add them to the
* attachment store. */
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