From d300de403de5b9b2d3c2c2f9d371f59859eeaf8c Mon Sep 17 00:00:00 2001 From: pepp Date: Thu, 15 Dec 2011 12:23:52 +0530 Subject: Bug 566793 - Support Drop And Drag Into Nautilus As PDF File --- mail/em-format-html-print.c | 28 +++-- mail/em-format-html-print.h | 3 + mail/em-format-html.c | 46 +++++++- mail/em-format-html.h | 6 + mail/em-utils.c | 252 +++++++++++++++++++++++++++++++---------- mail/evolution-mail.schemas.in | 32 ++++++ 6 files changed, 293 insertions(+), 74 deletions(-) diff --git a/mail/em-format-html-print.c b/mail/em-format-html-print.c index fd47275e30..d1e7dfb752 100644 --- a/mail/em-format-html-print.c +++ b/mail/em-format-html-print.c @@ -45,6 +45,8 @@ efhp_finalize (GObject *object) { EMFormatHTMLPrint *efhp = (EMFormatHTMLPrint *) object; + g_free (efhp->export_filename); + efhp->export_filename = NULL; gtk_widget_destroy (efhp->window); if (efhp->source != NULL) g_object_unref (efhp->source); @@ -90,6 +92,9 @@ em_format_html_print_init (EMFormatHTMLPrint *efhp) gtk_widget_realize (GTK_WIDGET (web_view)); efhp->parent.show_icon = FALSE; ((EMFormat *) efhp)->print = TRUE; + + efhp->export_filename = NULL; + efhp->async = TRUE; } EMFormatHTMLPrint * @@ -184,6 +189,9 @@ emfhp_complete (EMFormatHTMLPrint *efhp) operation = e_print_operation_new (); + if (efhp->action == GTK_PRINT_OPERATION_ACTION_EXPORT) + gtk_print_operation_set_export_filename (operation, efhp->export_filename); + gtk_html_print_operation_run ( GTK_HTML (web_view), operation, efhp->action, NULL, @@ -213,12 +221,18 @@ em_format_html_print_message (EMFormatHTMLPrint *efhp, em_format_html_load_images (EM_FORMAT_HTML (efhp)); - g_signal_connect ( - efhp, "complete", G_CALLBACK (emfhp_complete), efhp); - /* FIXME Not passing a GCancellable here. */ - em_format_format_clone ( - EM_FORMAT (efhp), - folder, message_uid, message, - EM_FORMAT (efhp->source), NULL); + if (efhp->async) { + g_signal_connect ( + efhp, "complete", G_CALLBACK (emfhp_complete), efhp); + + /* FIXME Not passing a GCancellable here. */ + em_format_format_clone ( + (EMFormat *) efhp, + folder, message_uid, message, + (EMFormat *) efhp->source, NULL); + } else { + em_format_html_clone_sync (folder, message_uid, message, (EMFormatHTML *)efhp, (EMFormat *)efhp->source); + emfhp_complete (efhp); + } } diff --git a/mail/em-format-html-print.h b/mail/em-format-html-print.h index c33669651d..5f08b6ef82 100644 --- a/mail/em-format-html-print.h +++ b/mail/em-format-html-print.h @@ -56,6 +56,9 @@ struct _EMFormatHTMLPrint { EMFormatHTML *source; GtkPrintOperationAction action; + gchar *export_filename; + + gboolean async; }; struct _EMFormatHTMLPrintClass { diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 960cdc1267..55f7aa9841 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -329,7 +329,7 @@ static MailMsgInfo efh_format_info = { }; static gboolean -efh_format_timeout (struct _format_msg *m) +efh_format_helper (struct _format_msg *m, gboolean async) { GtkHTMLStream *hstream; EMFormatHTML *efh = m->format; @@ -343,10 +343,12 @@ efh_format_timeout (struct _format_msg *m) return FALSE; } - d(printf("timeout called ...\n")); - if (p->format_id != -1) { - d(printf(" still waiting for cancellation to take effect, waiting ...\n")); - return TRUE; + if (async) { + d(printf("timeout called ...\n")); + if (p->format_id != -1) { + d(printf(" still waiting for cancellation to take effect, waiting ...\n")); + return TRUE; + } } g_return_val_if_fail (g_queue_is_empty (&p->pending_jobs), FALSE); @@ -400,7 +402,12 @@ efh_format_timeout (struct _format_msg *m) } efh->priv->format_id = m->base.seq; - mail_msg_unordered_push (m); + + if (async) { + mail_msg_unordered_push (m); + } else { + efh_format_exec(m, NULL, NULL); + } } efh->priv->format_timeout_id = 0; @@ -666,6 +673,32 @@ efh_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static gboolean +efh_format_timeout (struct _format_msg *m) +{ + return efh_format_helper (m, TRUE); +} + +void +em_format_html_clone_sync (CamelFolder *folder, + const gchar *uid, + CamelMimeMessage *msg, + EMFormatHTML *efh, + EMFormat *source) +{ + struct _format_msg *m; + + m = mail_msg_new (&efh_format_info); + m->format = efh; + m->format_source = source; + m->folder = folder; + m->uid = g_strdup (uid); + m->message = msg; + + efh_format_helper (m, FALSE); + efh_format_free (m); +} + static void efh_format_clone (EMFormat *emf, CamelFolder *folder, @@ -3399,3 +3432,4 @@ em_format_html_get_cached_image (EMFormatHTML *efh, return camel_data_cache_get ( emfh_http_cache, EMFH_HTTP_CACHE_PATH, image_uri, NULL); } + diff --git a/mail/em-format-html.h b/mail/em-format-html.h index 1efd7d0be6..7ded2e82f9 100644 --- a/mail/em-format-html.h +++ b/mail/em-format-html.h @@ -291,6 +291,12 @@ EMFormatHTMLJob * gpointer data); void em_format_html_job_queue (EMFormatHTML *efh, EMFormatHTMLJob *job); +void em_format_html_clone_sync (CamelFolder *folder, + const gchar *message_uid, + CamelMimeMessage *message, + EMFormatHTML *efh, + EMFormat *source); + gboolean em_format_html_get_show_real_date (EMFormatHTML *efh); void em_format_html_set_show_real_date diff --git a/mail/em-utils.c b/mail/em-utils.c index bfda4056be..96f912a153 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -70,6 +70,7 @@ #include "em-utils.h" #include "em-composer-utils.h" #include "em-format-quote.h" +#include "em-format-html-print.h" #include "e-mail-folder-utils.h" #include "e-mail-session.h" @@ -81,6 +82,12 @@ extern const gchar *shell_builtin_backend; /* Used in em_util_ask_open_many() */ #define TOO_MANY 10 +/* drag and drop resulting file naming possibilities */ +enum { + DND_USE_SENT_DATE = 1, /* YYYYMMDDhhmmssms_ and use email sent date */ + DND_USE_DND_DATE = 2, /* YYYYMMDDhhmmssms_<title> and drag'drop date */ +}; + #define d(x) gboolean @@ -603,6 +610,30 @@ em_utils_write_messages_to_stream (CamelFolder *folder, return res; } +static gboolean +em_utils_print_messages_to_file (CamelFolder *folder, + const gchar * uid, + const gchar *filename) +{ + EMFormatHTMLPrint *efhp; + CamelMimeMessage *message; + + message = camel_folder_get_message_sync (folder, uid, NULL, NULL); + if (message == NULL) + return FALSE; + + efhp = em_format_html_print_new (NULL, GTK_PRINT_OPERATION_ACTION_EXPORT); + efhp->export_filename = g_strdup (filename); + efhp->async = FALSE; + + em_format_html_print_message (efhp, message, folder, uid); + + g_object_unref (efhp); + g_object_unref (message); + + return TRUE; +} + /* This kind of sucks, because for various reasons most callers need to run * synchronously in the gui thread, however this could take a long, blocking * time to run. */ @@ -846,6 +877,59 @@ em_utils_selection_get_uidlist (GtkSelectionData *selection_data, em_utils_uids_free (uids); } +static gchar * +em_utils_build_export_filename (CamelFolder *folder, + const gchar * uid, + const gchar * exporttype, + gint exportname, + const gchar * tmpdir) +{ + CamelMessageInfo *info; + gchar *file, *tmpfile; + struct tm *ts; + gchar datetmp[15]; + + /* Try to get the drop filename from the message or folder */ + info = camel_folder_get_message_info(folder, uid); + if (info) { + if (camel_message_info_subject (info)) { + time_t reftime; + reftime = camel_message_info_date_sent (info); + if (exportname==DND_USE_DND_DATE) { + reftime = time(NULL); + } + + ts = localtime(&reftime); + strftime(datetmp, 15, "%Y%m%d%H%M%S", ts); + + if (g_ascii_strcasecmp (exporttype, "pdf")==0) + file = g_strdup_printf ("%s_%s.pdf", datetmp, camel_message_info_subject (info)); + else + file = g_strdup_printf ("%s_%s", datetmp, camel_message_info_subject(info)); + + } + camel_folder_free_message_info(folder, info); + } else { + time_t reftime; + reftime = time(NULL); + ts = localtime(&reftime); + strftime(datetmp, 15, "%Y%m%d%H%M%S", ts); + if (g_ascii_strcasecmp (exporttype, "pdf")==0) + file = g_strdup_printf ("%s_Untitled Message.pdf", datetmp); + else + file = g_strdup_printf ("%s_Untitled Message", datetmp); + + } + + e_filename_make_safe(file); + + tmpfile = g_build_filename(tmpdir, file, NULL); + + g_free(file); + + return tmpfile; +} + /** * em_utils_selection_set_urilist: * @data: @@ -861,69 +945,115 @@ em_utils_selection_set_urilist (GtkSelectionData *data, CamelFolder *folder, GPtrArray *uids) { - gchar *tmpdir; - CamelStream *fstream; - gchar *uri, *file = NULL, *tmpfile; - gint fd; - CamelMessageInfo *info; - - tmpdir = e_mkdtemp("drag-n-drop-XXXXXX"); - if (tmpdir == NULL) - return; - - /* Try to get the drop filename from the message or folder */ - if (uids->len == 1) { - const gchar *message_uid; - - message_uid = g_ptr_array_index (uids, 0); - info = camel_folder_get_message_info (folder, message_uid); - if (info) { - file = g_strdup (camel_message_info_subject (info)); - camel_folder_free_message_info (folder, info); + gchar *tmpdir; + gchar *uri; + gint fd; + GConfClient *client; + gchar *exporttype; + gint exportname; + + tmpdir = e_mkdtemp("drag-n-drop-XXXXXX"); + if (tmpdir == NULL) + return; + + client = gconf_client_get_default (); + exporttype = gconf_client_get_string ( + client, "/apps/evolution/mail/save_file_format", NULL); + if (exporttype == NULL) + exporttype = g_strdup ("mbox"); + exportname = gconf_client_get_int ( + client, "/apps/evolution/mail/save_name_format", NULL); + + if (g_ascii_strcasecmp (exporttype, "mbox")==0) { + gchar * file = NULL; + CamelStream *fstream; + + if(uids->len>1) { + gchar * tmp = g_strdup_printf(_("Messages from %s"), camel_folder_get_display_name (folder)); + e_filename_make_safe(tmp); + file = g_build_filename(tmpdir, tmp, NULL); + g_free(tmp); + } else { + file = em_utils_build_export_filename(folder, uids->pdata[0], exporttype, exportname, tmpdir); + } + + g_free(tmpdir); + fd = g_open(file, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0666); + if (fd == -1) { + g_free(file); + g_free(exporttype); + return; + } + + uri = g_filename_to_uri(file, NULL, NULL); + fstream = camel_stream_fs_new_with_fd(fd); + if (fstream) { + if (em_utils_write_messages_to_stream(folder, uids, fstream) == 0) { + GdkAtom type; + /* terminate with \r\n to be compliant with the spec */ + gchar *uri_crlf = g_strconcat(uri, "\r\n", NULL); + + type = gtk_selection_data_get_target (data); + gtk_selection_data_set(data, type, 8, (guchar *) uri_crlf, strlen(uri_crlf)); + g_free(uri_crlf); + } + g_object_unref (fstream); + } else + close(fd); + + g_free(exporttype); + g_free(file); + g_free(uri); + } else if(g_ascii_strcasecmp (exporttype, "pdf")==0) { + gchar ** filenames, **uris; + gint i, uris_count=0; + + filenames = g_new(gchar *, uids->len); + uris = g_new(gchar *, uids->len + 1); + for(i=0; i<uids->len; i++) { + filenames[i] = em_utils_build_export_filename(folder, uids->pdata[i], exporttype, exportname, tmpdir); + /* validity test */ + fd = g_open(filenames[i], O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0666); + if (fd == -1) { + gint j; + for(j=0; j<=i; j++) { + g_free(filenames[j]); + } + g_free(filenames); + g_free(uris); + g_free(tmpdir); + g_free(exporttype); + return; + } + close(fd); + + /* export */ + if (em_utils_print_messages_to_file (folder, uids->pdata[i], filenames[i])) { + /* terminate with \r\n to be compliant with the spec */ + uri = g_filename_to_uri(filenames[i], NULL, NULL); + uris[uris_count++] = g_strconcat(uri, "\r\n", NULL); + g_free(uri); + } + } + + uris[uris_count] = NULL; + gtk_selection_data_set_uris(data, uris); + + g_free(tmpdir); + for(i=0; i<uids->len; i++) { + g_free(filenames[i]); + } + g_free(filenames); + for(i=0; i<uris_count; i++) { + g_free(uris[i]); } + g_free(uris); + g_free(exporttype); + + } else { + g_free(tmpdir); + g_free(exporttype); } - - /* TODO: Handle conflicts? */ - if (file == NULL) { - /* Drop filename for messages from a mailbox */ - file = g_strdup_printf ( - _("Messages from %s"), - camel_folder_get_display_name (folder)); - } - - e_filename_make_safe (file); - - tmpfile = g_build_filename (tmpdir, file, NULL); - g_free (tmpdir); - g_free (file); - - fd = g_open (tmpfile, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0666); - if (fd == -1) { - g_free (tmpfile); - return; - } - - uri = g_filename_to_uri (tmpfile, NULL, NULL); - g_free (tmpfile); - fstream = camel_stream_fs_new_with_fd (fd); - if (fstream) { - if (em_utils_write_messages_to_stream (folder, uids, fstream) == 0) { - /* terminate with \r\n to be compliant with the spec */ - gchar *uri_crlf = g_strconcat(uri, "\r\n", NULL); - GdkAtom target; - - target = gtk_selection_data_get_target (data); - gtk_selection_data_set ( - data, target, 8, (guchar *) - uri_crlf, strlen (uri_crlf)); - g_free (uri_crlf); - } - - g_object_unref (fstream); - } else - close (fd); - - g_free (uri); } /** diff --git a/mail/evolution-mail.schemas.in b/mail/evolution-mail.schemas.in index f7c3844b8a..79d9c59d9e 100644 --- a/mail/evolution-mail.schemas.in +++ b/mail/evolution-mail.schemas.in @@ -1775,6 +1775,38 @@ </locale> </schema> + <!-- email drag'n'drop settings --> + + <schema> + <key>/schemas/apps/evolution/mail/save_file_format</key> + <applyto>/apps/evolution/mail/save_file_format</applyto> + <owner>evolution-mail</owner> + <type>string</type> + <default>mbox</default> + <locale name="C"> + <short>Drag'n'drop export format</short> + <long> + Define the email export format when doing drag'n'drop. + Possible values are : mbox or pdf + </long> + </locale> + </schema> + + <schema> + <key>/schemas/apps/evolution/mail/save_name_format</key> + <applyto>/apps/evolution/mail/save_name_format</applyto> + <owner>evolution-mail</owner> + <type>int</type> + <default>1</default> + <locale name="C"> + <short>Format of the drag'n'drop export filename</short> + <long> + Exported file name will be : YYYmmDDHHMMSS_email_title + Possible values : 1 (: email sent date), 2 (: drag'n'drop date) + </long> + </locale> + </schema> + <!-- Others --> <schema> -- cgit