aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--libsylph/libsylph-0.def2
-rw-r--r--libsylph/procmsg.c196
-rw-r--r--libsylph/procmsg.h7
-rw-r--r--libsylph/utils.c31
-rw-r--r--libsylph/utils.h6
-rw-r--r--src/filesel.c76
-rw-r--r--src/filesel.h6
-rw-r--r--src/summaryview.c30
9 files changed, 302 insertions, 60 deletions
diff --git a/ChangeLog b/ChangeLog
index 84152802..a4ad2c8a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
}