Kill more redundant save functions.
This commit is contained in:
239
mail/em-utils.c
239
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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 *
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user