diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | libsylph/libsylph-0.def | 2 | ||||
-rw-r--r-- | libsylph/procmsg.c | 196 | ||||
-rw-r--r-- | libsylph/procmsg.h | 7 | ||||
-rw-r--r-- | libsylph/utils.c | 31 | ||||
-rw-r--r-- | libsylph/utils.h | 6 | ||||
-rw-r--r-- | src/filesel.c | 76 | ||||
-rw-r--r-- | src/filesel.h | 6 | ||||
-rw-r--r-- | src/summaryview.c | 30 |
9 files changed, 302 insertions, 60 deletions
@@ -1,3 +1,11 @@ +2013-04-03 + + * libsylph/utils.[ch] + libsylph/procmsg.[ch] + src/filesel.[ch] + src/summaryview.c: added the feature to save message as plain text + (locale or UTF-8 encoding). + 2013-03-29 * version 3.4.0beta3 diff --git a/libsylph/libsylph-0.def b/libsylph/libsylph-0.def index 325ecac4..7bcf893d 100644 --- a/libsylph/libsylph-0.def +++ b/libsylph/libsylph-0.def @@ -708,3 +708,5 @@ EXPORTS folder_get_ui_func2 @ 706
folder_call_ui_func2 @ 707
export_msgs_to_mbox @ 708
+ copy_file_stream @ 709
+ procmsg_save_message_as_text @ 710
diff --git a/libsylph/procmsg.c b/libsylph/procmsg.c index 525f9b47..d833c177 100644 --- a/libsylph/procmsg.c +++ b/libsylph/procmsg.c @@ -1,6 +1,6 @@ /* * LibSylph -- E-Mail client library - * Copyright (C) 1999-2011 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1725,13 +1725,74 @@ static gint print_command_exec(const gchar *file, const gchar *cmdline) return 0; } +static void procmsg_write_headers(MsgInfo *msginfo, MimeInfo *partinfo, + FILE *fp, FILE *dest_fp, + const gchar *encoding, gboolean all_headers) +{ + GPtrArray *headers; + gint i; + + if (all_headers) + headers = procheader_get_header_array_asis(fp, NULL); + else + headers = procheader_get_header_array_for_display(fp, NULL); + + for (i = 0; i < headers->len; i++) { + Header *hdr; + gchar *file_str; + const gchar *body; + + hdr = g_ptr_array_index(headers, i); + + if (partinfo) { + if (!g_ascii_strcasecmp(hdr->name, "Subject") || + !g_ascii_strcasecmp(hdr->name, "From") || + !g_ascii_strcasecmp(hdr->name, "To") || + !g_ascii_strcasecmp(hdr->name, "Cc")) { + unfold_line(hdr->body); + } + + body = hdr->body; + while (g_ascii_isspace(*body)) + body++; + } else { + if (!g_ascii_strcasecmp(hdr->name, "Subject")) + body = msginfo->subject; + else if (!g_ascii_strcasecmp(hdr->name, "From")) + body = msginfo->from; + else if (!g_ascii_strcasecmp(hdr->name, "To")) + body = msginfo->to; + else if (!g_ascii_strcasecmp(hdr->name, "Cc")) { + unfold_line(hdr->body); + body = hdr->body; + while (g_ascii_isspace(*body)) + body++; + } else { + body = hdr->body; + while (g_ascii_isspace(*body)) + body++; + } + } + + if (body && *body != '\0') { + file_str = conv_codeset_strdup + (body, CS_INTERNAL, encoding); + fprintf(dest_fp, "%s: %s\n", hdr->name, + file_str ? file_str : body); + g_free(file_str); + } else { + fprintf(dest_fp, "%s: (none)\n", hdr->name); + } + } + + procheader_header_array_destroy(headers); +} + void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline, gboolean all_headers) { gchar *prtmp; FILE *msgfp, *tmpfp, *prfp; - GPtrArray *headers; - gint i; gchar buf[BUFFSIZE]; g_return_if_fail(msginfo != NULL); @@ -1760,51 +1821,11 @@ void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline, return; } - if (all_headers) - headers = procheader_get_header_array_asis(msgfp, NULL); - else - headers = procheader_get_header_array_for_display(msgfp, NULL); + procmsg_write_headers(msginfo, NULL, msgfp, prfp, + conv_get_locale_charset_str(), all_headers); fclose(msgfp); - for (i = 0; i < headers->len; i++) { - Header *hdr; - gchar *locale_str; - const gchar *body; - - hdr = g_ptr_array_index(headers, i); - - if (!g_ascii_strcasecmp(hdr->name, "Subject")) - body = msginfo->subject; - else if (!g_ascii_strcasecmp(hdr->name, "From")) - body = msginfo->from; - else if (!g_ascii_strcasecmp(hdr->name, "To")) - body = msginfo->to; - else if (!g_ascii_strcasecmp(hdr->name, "Cc")) { - unfold_line(hdr->body); - body = hdr->body; - while (g_ascii_isspace(*body)) - body++; - } else { - body = hdr->body; - while (g_ascii_isspace(*body)) - body++; - } - - if (body && *body != '\0') { - locale_str = conv_codeset_strdup - (body, CS_INTERNAL, - conv_get_locale_charset_str()); - fprintf(prfp, "%s: %s\n", hdr->name, - locale_str ? locale_str : body); - g_free(locale_str); - } else { - fprintf(prfp, "%s: (none)\n", hdr->name); - } - } - - procheader_header_array_destroy(headers); - fputc('\n', prfp); while (fgets(buf, sizeof(buf), tmpfp) != NULL) @@ -1857,6 +1878,91 @@ void procmsg_print_message_part(MsgInfo *msginfo, MimeInfo *partinfo, g_free(prtmp); } +gint procmsg_save_message_as_text(MsgInfo *msginfo, const gchar *dest, + const gchar *encoding, gboolean all_headers) +{ + MimeInfo *mimeinfo, *partinfo; + FILE *fp; + FILE *tmpfp; + FILE *destfp; + gchar buf[BUFFSIZE]; + + g_return_val_if_fail(msginfo != NULL, -1); + g_return_val_if_fail(dest != NULL, -1); + + mimeinfo = procmime_scan_message(msginfo); + if (!mimeinfo) + return -1; + if ((fp = procmsg_open_message(msginfo)) == NULL) { + procmime_mimeinfo_free_all(mimeinfo); + return -1; + } + if ((destfp = g_fopen(dest, "wb")) == NULL) { + fclose(fp); + procmime_mimeinfo_free_all(mimeinfo); + return -1; + } + procmsg_write_headers(msginfo, mimeinfo, fp, destfp, encoding, all_headers); + fputc('\n', destfp); + + partinfo = mimeinfo; + + while (partinfo != NULL) { + if (fseek(fp, partinfo->fpos, SEEK_SET) < 0) + break; + + if (partinfo->filename || partinfo->name) + g_snprintf(buf, sizeof(buf), "\n[%s %s (%s)]\n", + partinfo->filename ? partinfo->filename : + partinfo->name, + partinfo->content_type, + to_human_readable(partinfo->content_size)); + else + g_snprintf(buf, sizeof(buf), "\n[%s (%s)]\n", + partinfo->content_type, + to_human_readable(partinfo->content_size)); + + if (partinfo->mime_type == MIME_TEXT || + partinfo->mime_type == MIME_TEXT_HTML) { + if (!partinfo->main && + partinfo->parent && + partinfo->parent->children != partinfo) { + fputs(buf, destfp); + } + + if ((tmpfp = procmime_get_text_content(partinfo, fp, encoding)) == NULL) + break; + if (copy_file_stream(tmpfp, destfp) < 0) { + fclose(tmpfp); + break; + } + + fclose(tmpfp); + } else if (partinfo->mime_type == MIME_MESSAGE_RFC822) { + fputs(buf, destfp); + while (fgets(buf, sizeof(buf), fp) != NULL) + if (buf[0] == '\r' || buf[0] == '\n') break; + procmsg_write_headers(msginfo, partinfo, fp, destfp, encoding, all_headers); + fputc('\n', destfp); + } else if (partinfo->mime_type != MIME_MULTIPART) { + fputs(buf, destfp); + } + + if (partinfo->parent && partinfo->parent->content_type && + !g_ascii_strcasecmp(partinfo->parent->content_type, + "multipart/alternative")) + partinfo = partinfo->parent->next; + else + partinfo = procmime_mimeinfo_next(partinfo); + } + + fclose(destfp); + fclose(fp); + procmime_mimeinfo_free_all(mimeinfo); + + return 0; +} + /** * procmsg_concat_partial_messages: * @mlist: list of MsgInfo* including message/partial messages. diff --git a/libsylph/procmsg.h b/libsylph/procmsg.h index 1130c7cb..92a6be8b 100644 --- a/libsylph/procmsg.h +++ b/libsylph/procmsg.h @@ -1,6 +1,6 @@ /* * LibSylph -- E-Mail client library - * Copyright (C) 1999-2011 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -329,6 +329,11 @@ void procmsg_print_message_part (MsgInfo *msginfo, const gchar *cmdline, gboolean all_headers); +gint procmsg_save_message_as_text (MsgInfo *msginfo, + const gchar *dest, + const gchar *encoding, + gboolean all_headers); + gint procmsg_concat_partial_messages (GSList *mlist, const gchar *file); diff --git a/libsylph/utils.c b/libsylph/utils.c index f8431a3e..474d96a6 100644 --- a/libsylph/utils.c +++ b/libsylph/utils.c @@ -1,6 +1,6 @@ /* * LibSylph -- E-Mail client library - * Copyright (C) 1999-2012 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -3123,6 +3123,35 @@ gint copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest) return 0; } +gint copy_file_stream(FILE *fp, FILE *dest_fp) +{ + gint n_read; + gchar buf[BUFFSIZE]; + + g_return_val_if_fail(fp != NULL, -1); + g_return_val_if_fail(dest_fp != NULL, -1); + + while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) { + if (n_read < sizeof(buf) && ferror(fp)) + break; + if (fwrite(buf, n_read, 1, dest_fp) < 1) { + g_warning("copy_file_stream: writing to file failed.\n"); + return -1; + } + } + + if (ferror(fp)) { + perror("fread"); + return -1; + } + if (fflush(dest_fp) == EOF) { + FILE_OP_ERROR("copy_file_stream", "fflush"); + return -1; + } + + return 0; +} + /* convert line endings into CRLF. If the last line doesn't end with * linebreak, add it. */ diff --git a/libsylph/utils.h b/libsylph/utils.h index a67a807a..79ece425 100644 --- a/libsylph/utils.h +++ b/libsylph/utils.h @@ -1,6 +1,6 @@ /* * LibSylph -- E-Mail client library - * Copyright (C) 1999-2012 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -453,6 +453,7 @@ gint copy_dir (const gchar *src, gint move_file (const gchar *src, const gchar *dest, gboolean overwrite); + gint append_file_part (FILE *fp, off_t offset, size_t length, @@ -462,6 +463,9 @@ gint copy_file_part (FILE *fp, size_t length, const gchar *dest); +gint copy_file_stream (FILE *fp, + FILE *dest_fp); + gchar *canonicalize_str (const gchar *str); gint canonicalize_file (const gchar *src, const gchar *dest); diff --git a/src/filesel.c b/src/filesel.c index abf6ad1f..593b54f6 100644 --- a/src/filesel.c +++ b/src/filesel.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2012 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,7 @@ #include <gtk/gtkversion.h> #include <gtk/gtkfilechooserdialog.h> #include <gtk/gtkexpander.h> +#include <gtk/gtkcombobox.h> #include <gtk/gtkstock.h> #ifdef G_OS_WIN32 @@ -45,7 +46,10 @@ static GSList *filesel_select_file_full (const gchar *title, const gchar *file, GtkFileChooserAction action, - gboolean multiple); + gboolean multiple, + GSList *types, + gint default_type, + gint *selected_type); static GtkWidget *filesel_create (const gchar *title, GtkFileChooserAction action); @@ -74,7 +78,7 @@ gchar *filesel_select_file(const gchar *title, const gchar *file, GSList *list; gchar *selected = NULL; - list = filesel_select_file_full(title, file, action, FALSE); + list = filesel_select_file_full(title, file, action, FALSE, NULL, 0, NULL); if (list) { selected = (gchar *)list->data; slist_free_strings(list->next); @@ -87,7 +91,7 @@ gchar *filesel_select_file(const gchar *title, const gchar *file, GSList *filesel_select_files(const gchar *title, const gchar *file, GtkFileChooserAction action) { - return filesel_select_file_full(title, file, action, TRUE); + return filesel_select_file_full(title, file, action, TRUE, NULL, 0, NULL); } static void filesel_change_dir_for_action(GtkFileChooserAction action) @@ -155,13 +159,16 @@ static void filesel_save_dir_for_action(GtkFileChooserAction action, static GSList *filesel_select_file_full(const gchar *title, const gchar *file, GtkFileChooserAction action, - gboolean multiple) + gboolean multiple, + GSList *types, + gint default_type, gint *selected_type) { gchar *cwd; GtkWidget *dialog; gchar *prev_dir; static gboolean save_expander_expanded = FALSE; GSList *list = NULL; + GtkWidget *combo = NULL; prev_dir = g_get_current_dir(); @@ -193,6 +200,27 @@ static GSList *filesel_select_file_full(const gchar *title, const gchar *file, } #endif + /* create types combo box */ + if (types) { + GSList *cur; + GtkWidget *hbox; + GtkWidget *label; + + hbox = gtk_hbox_new(FALSE, 12); + label = gtk_label_new(_("File type:")); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); + + combo = gtk_combo_box_new_text(); + for (cur = types; cur != NULL; cur = cur->next) { + gtk_combo_box_append_text(GTK_COMBO_BOX(combo), (const gchar *)cur->data); + } + gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0); + + gtk_widget_show_all(hbox); + gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), hbox); + gtk_combo_box_set_active(GTK_COMBO_BOX(combo), default_type); + } + gtk_widget_show(dialog); change_dir(prev_dir); @@ -230,6 +258,10 @@ again: inc_unlock(); + if (combo && selected_type) { + *selected_type = gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); + } + if (action == GTK_FILE_CHOOSER_ACTION_SAVE) save_expander_expanded = filesel_save_expander_get_expanded(dialog); @@ -264,6 +296,38 @@ gchar *filesel_save_as(const gchar *file) return filename; } +gchar *filesel_save_as_type(const gchar *file, GSList *types, + gint default_type, gint *selected_type) +{ + GSList *list; + gchar *filename = NULL; + + list = filesel_select_file_full(_("Save as"), file, + GTK_FILE_CHOOSER_ACTION_SAVE, FALSE, + types, default_type, selected_type); + if (list) { + filename = (gchar *)list->data; + slist_free_strings(list->next); + } + g_slist_free(list); + +#if !GTK_CHECK_VERSION(2, 8, 0) + if (filename && is_file_exist(filename)) { + AlertValue aval; + + aval = alertpanel(_("Overwrite existing file"), + _("The file already exists. Do you want to replace it?"), + GTK_STOCK_YES, GTK_STOCK_NO, NULL); + if (G_ALERTDEFAULT != aval) { + g_free(filename); + filename = NULL; + } + } +#endif + + return filename; +} + gchar *filesel_select_dir(const gchar *dir) { GSList *list; @@ -271,7 +335,7 @@ gchar *filesel_select_dir(const gchar *dir) list = filesel_select_file_full(_("Select folder"), dir, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - FALSE); + FALSE, NULL, 0, NULL); if (list) { selected = (gchar *)list->data; slist_free_strings(list->next); diff --git a/src/filesel.h b/src/filesel.h index b089a89a..c694ef24 100644 --- a/src/filesel.h +++ b/src/filesel.h @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2012 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +31,10 @@ GSList *filesel_select_files (const gchar *title, GtkFileChooserAction action); gchar *filesel_save_as (const gchar *file); +gchar *filesel_save_as_type (const gchar *file, + GSList *types, + gint default_type, + gint *selected_type); gchar *filesel_select_dir (const gchar *dir); #endif /* __FILESEL_H__ */ diff --git a/src/summaryview.c b/src/summaryview.c index d0f35735..c22a431c 100644 --- a/src/summaryview.c +++ b/src/summaryview.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2012 Hiroyuki Yamamoto + * Copyright (C) 1999-2013 Hiroyuki Yamamoto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -3891,6 +3891,10 @@ void summary_save_as(SummaryView *summaryview) MsgInfo *msginfo = NULL; gchar *filename; gchar *src, *dest; + GSList *types; + gint selected_type = 0; + gint result; + gboolean all_headers; if (!summaryview->selected) return; if (!gtkut_tree_row_reference_get_iter @@ -3908,14 +3912,31 @@ void summary_save_as(SummaryView *summaryview) } subst_for_filename(filename); - dest = filesel_save_as(filename); + types = g_slist_append(NULL, _("Original (EML/RFC 822)")); + types = g_slist_append(types, _("Text")); + types = g_slist_append(types, _("Text (UTF-8)")); + dest = filesel_save_as_type(filename, types, 0, &selected_type); + g_slist_free(types); g_free(filename); if (!dest) return; - src = procmsg_get_message_file(msginfo); - if (copy_file(src, dest, TRUE) < 0) { + debug_print("summary_save_as: selected_type: %d\n", selected_type); + + all_headers = summaryview->messageview->textview->show_all_headers; + + if (selected_type == 1) { + result = procmsg_save_message_as_text(msginfo, dest, conv_get_locale_charset_str(), all_headers); + } else if (selected_type == 2) { + result = procmsg_save_message_as_text(msginfo, dest, NULL, all_headers); + } else { + src = procmsg_get_message_file(msginfo); + result = copy_file(src, dest, TRUE); + g_free(src); + } + + if (result < 0) { gchar *utf8_dest; utf8_dest = conv_filename_to_utf8(dest); @@ -3923,7 +3944,6 @@ void summary_save_as(SummaryView *summaryview) g_basename(utf8_dest)); g_free(utf8_dest); } - g_free(src); g_free(dest); } |