Revision 3245

View differences:

libsylph/utils.c
1 1
/*
2 2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This library is free software; you can redistribute it and/or
6 6
 * modify it under the terms of the GNU Lesser General Public
......
3123 3123
	return 0;
3124 3124
}
3125 3125

  
3126
gint copy_file_stream(FILE *fp, FILE *dest_fp)
3127
{
3128
	gint n_read;
3129
	gchar buf[BUFFSIZE];
3130

  
3131
	g_return_val_if_fail(fp != NULL, -1);
3132
	g_return_val_if_fail(dest_fp != NULL, -1);
3133

  
3134
	while ((n_read = fread(buf, sizeof(gchar), sizeof(buf), fp)) > 0) {
3135
		if (n_read < sizeof(buf) && ferror(fp))
3136
			break;
3137
		if (fwrite(buf, n_read, 1, dest_fp) < 1) {
3138
			g_warning("copy_file_stream: writing to file failed.\n");
3139
			return -1;
3140
		}
3141
	}
3142

  
3143
	if (ferror(fp)) {
3144
		perror("fread");
3145
		return -1;
3146
	}
3147
	if (fflush(dest_fp) == EOF) {
3148
		FILE_OP_ERROR("copy_file_stream", "fflush");
3149
		return -1;
3150
	}
3151

  
3152
	return 0;
3153
}
3154

  
3126 3155
/* convert line endings into CRLF. If the last line doesn't end with
3127 3156
 * linebreak, add it.
3128 3157
 */
libsylph/utils.h
1 1
/*
2 2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This library is free software; you can redistribute it and/or
6 6
 * modify it under the terms of the GNU Lesser General Public
......
453 453
gint move_file			(const gchar	*src,
454 454
				 const gchar	*dest,
455 455
				 gboolean	 overwrite);
456

  
456 457
gint append_file_part		(FILE		*fp,
457 458
				 off_t		 offset,
458 459
				 size_t		 length,
......
462 463
				 size_t		 length,
463 464
				 const gchar	*dest);
464 465

  
466
gint copy_file_stream		(FILE		*fp,
467
				 FILE		*dest_fp);
468

  
465 469
gchar *canonicalize_str		(const gchar	*str);
466 470
gint canonicalize_file		(const gchar	*src,
467 471
				 const gchar	*dest);
libsylph/procmsg.c
1 1
/*
2 2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2011 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This library is free software; you can redistribute it and/or
6 6
 * modify it under the terms of the GNU Lesser General Public
......
1725 1725
	return 0;
1726 1726
}
1727 1727

  
1728
static void procmsg_write_headers(MsgInfo *msginfo, MimeInfo *partinfo,
1729
				  FILE *fp, FILE *dest_fp,
1730
				  const gchar *encoding, gboolean all_headers)
1731
{
1732
	GPtrArray *headers;
1733
	gint i;
1734

  
1735
	if (all_headers)
1736
		headers = procheader_get_header_array_asis(fp, NULL);
1737
	else
1738
		headers = procheader_get_header_array_for_display(fp, NULL);
1739

  
1740
	for (i = 0; i < headers->len; i++) {
1741
		Header *hdr;
1742
		gchar *file_str;
1743
		const gchar *body;
1744

  
1745
		hdr = g_ptr_array_index(headers, i);
1746

  
1747
		if (partinfo) {
1748
			if (!g_ascii_strcasecmp(hdr->name, "Subject") ||
1749
			    !g_ascii_strcasecmp(hdr->name, "From") ||
1750
			    !g_ascii_strcasecmp(hdr->name, "To") ||
1751
			    !g_ascii_strcasecmp(hdr->name, "Cc")) {
1752
				unfold_line(hdr->body);
1753
			}
1754

  
1755
			body = hdr->body;
1756
			while (g_ascii_isspace(*body))
1757
				body++;
1758
		} else {
1759
			if (!g_ascii_strcasecmp(hdr->name, "Subject"))
1760
				body = msginfo->subject;
1761
			else if (!g_ascii_strcasecmp(hdr->name, "From"))
1762
				body = msginfo->from;
1763
			else if (!g_ascii_strcasecmp(hdr->name, "To"))
1764
				body = msginfo->to;
1765
			else if (!g_ascii_strcasecmp(hdr->name, "Cc")) {
1766
				unfold_line(hdr->body);
1767
				body = hdr->body;
1768
				while (g_ascii_isspace(*body))
1769
					body++;
1770
			} else {
1771
				body = hdr->body;
1772
				while (g_ascii_isspace(*body))
1773
					body++;
1774
			}
1775
		}
1776

  
1777
		if (body && *body != '\0') {
1778
			file_str = conv_codeset_strdup
1779
				(body, CS_INTERNAL, encoding);
1780
			fprintf(dest_fp, "%s: %s\n", hdr->name,
1781
				file_str ? file_str : body);
1782
			g_free(file_str);
1783
		} else {
1784
			fprintf(dest_fp, "%s: (none)\n", hdr->name);
1785
		}
1786
	}
1787

  
1788
	procheader_header_array_destroy(headers);
1789
}
1790

  
1728 1791
void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline,
1729 1792
			   gboolean all_headers)
1730 1793
{
1731 1794
	gchar *prtmp;
1732 1795
	FILE *msgfp, *tmpfp, *prfp;
1733
	GPtrArray *headers;
1734
	gint i;
1735 1796
	gchar buf[BUFFSIZE];
1736 1797

  
1737 1798
	g_return_if_fail(msginfo != NULL);
......
1760 1821
		return;
1761 1822
	}
1762 1823

  
1763
	if (all_headers)
1764
		headers = procheader_get_header_array_asis(msgfp, NULL);
1765
	else
1766
		headers = procheader_get_header_array_for_display(msgfp, NULL);
1824
	procmsg_write_headers(msginfo, NULL, msgfp, prfp,
1825
			      conv_get_locale_charset_str(), all_headers);
1767 1826

  
1768 1827
	fclose(msgfp);
1769 1828

  
1770
	for (i = 0; i < headers->len; i++) {
1771
		Header *hdr;
1772
		gchar *locale_str;
1773
		const gchar *body;
1774

  
1775
		hdr = g_ptr_array_index(headers, i);
1776

  
1777
		if (!g_ascii_strcasecmp(hdr->name, "Subject"))
1778
			body = msginfo->subject;
1779
		else if (!g_ascii_strcasecmp(hdr->name, "From"))
1780
			body = msginfo->from;
1781
		else if (!g_ascii_strcasecmp(hdr->name, "To"))
1782
			body = msginfo->to;
1783
		else if (!g_ascii_strcasecmp(hdr->name, "Cc")) {
1784
			unfold_line(hdr->body);
1785
			body = hdr->body;
1786
			while (g_ascii_isspace(*body))
1787
				body++;
1788
		} else {
1789
			body = hdr->body;
1790
			while (g_ascii_isspace(*body))
1791
				body++;
1792
		}
1793

  
1794
		if (body && *body != '\0') {
1795
			locale_str = conv_codeset_strdup
1796
				(body, CS_INTERNAL,
1797
				 conv_get_locale_charset_str());
1798
			fprintf(prfp, "%s: %s\n", hdr->name,
1799
				locale_str ? locale_str : body);
1800
			g_free(locale_str);
1801
		} else {
1802
			fprintf(prfp, "%s: (none)\n", hdr->name);
1803
		}
1804
	}
1805

  
1806
	procheader_header_array_destroy(headers);
1807

  
1808 1829
	fputc('\n', prfp);
1809 1830

  
1810 1831
	while (fgets(buf, sizeof(buf), tmpfp) != NULL)
......
1857 1878
	g_free(prtmp);
1858 1879
}
1859 1880

  
1881
gint procmsg_save_message_as_text(MsgInfo *msginfo, const gchar *dest,
1882
				  const gchar *encoding, gboolean all_headers)
1883
{
1884
	MimeInfo *mimeinfo, *partinfo;
1885
	FILE *fp;
1886
	FILE *tmpfp;
1887
	FILE *destfp;
1888
	gchar buf[BUFFSIZE];
1889

  
1890
	g_return_val_if_fail(msginfo != NULL, -1);
1891
	g_return_val_if_fail(dest != NULL, -1);
1892

  
1893
	mimeinfo = procmime_scan_message(msginfo);
1894
	if (!mimeinfo)
1895
		return -1;
1896
	if ((fp = procmsg_open_message(msginfo)) == NULL) {
1897
		procmime_mimeinfo_free_all(mimeinfo);
1898
		return -1;
1899
	}
1900
	if ((destfp = g_fopen(dest, "wb")) == NULL) {
1901
		fclose(fp);
1902
		procmime_mimeinfo_free_all(mimeinfo);
1903
		return -1;
1904
	}
1905
	procmsg_write_headers(msginfo, mimeinfo, fp, destfp, encoding, all_headers);
1906
	fputc('\n', destfp);
1907

  
1908
	partinfo = mimeinfo;
1909

  
1910
	while (partinfo != NULL) {
1911
		if (fseek(fp, partinfo->fpos, SEEK_SET) < 0)
1912
			break;
1913

  
1914
		if (partinfo->filename || partinfo->name)
1915
			g_snprintf(buf, sizeof(buf), "\n[%s  %s (%s)]\n",
1916
				   partinfo->filename ? partinfo->filename :
1917
				   partinfo->name,
1918
				   partinfo->content_type,
1919
				   to_human_readable(partinfo->content_size));
1920
		else
1921
			g_snprintf(buf, sizeof(buf), "\n[%s (%s)]\n",
1922
				   partinfo->content_type,
1923
				   to_human_readable(partinfo->content_size));
1924

  
1925
		if (partinfo->mime_type == MIME_TEXT ||
1926
		    partinfo->mime_type == MIME_TEXT_HTML) {
1927
			if (!partinfo->main &&
1928
			    partinfo->parent &&
1929
			    partinfo->parent->children != partinfo) {
1930
				fputs(buf, destfp);
1931
			}
1932

  
1933
			if ((tmpfp = procmime_get_text_content(partinfo, fp, encoding)) == NULL)
1934
				break;
1935
			if (copy_file_stream(tmpfp, destfp) < 0) {
1936
				fclose(tmpfp);
1937
				break;
1938
			}
1939

  
1940
			fclose(tmpfp);
1941
		} else if (partinfo->mime_type == MIME_MESSAGE_RFC822) {
1942
			fputs(buf, destfp);
1943
			while (fgets(buf, sizeof(buf), fp) != NULL)
1944
				if (buf[0] == '\r' || buf[0] == '\n') break;
1945
			procmsg_write_headers(msginfo, partinfo, fp, destfp, encoding, all_headers);
1946
			fputc('\n', destfp);
1947
		} else if (partinfo->mime_type != MIME_MULTIPART) {
1948
			fputs(buf, destfp);
1949
		}
1950

  
1951
		if (partinfo->parent && partinfo->parent->content_type &&
1952
		    !g_ascii_strcasecmp(partinfo->parent->content_type,
1953
					"multipart/alternative"))
1954
			partinfo = partinfo->parent->next;
1955
		else
1956
			partinfo = procmime_mimeinfo_next(partinfo);
1957
	}
1958

  
1959
	fclose(destfp);
1960
	fclose(fp);
1961
	procmime_mimeinfo_free_all(mimeinfo);
1962

  
1963
	return 0;
1964
}
1965

  
1860 1966
/**
1861 1967
 * procmsg_concat_partial_messages:
1862 1968
 * @mlist: list of MsgInfo* including message/partial messages.
libsylph/procmsg.h
1 1
/*
2 2
 * LibSylph -- E-Mail client library
3
 * Copyright (C) 1999-2011 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This library is free software; you can redistribute it and/or
6 6
 * modify it under the terms of the GNU Lesser General Public
......
329 329
					 const gchar	*cmdline,
330 330
					 gboolean	 all_headers);
331 331

  
332
gint	procmsg_save_message_as_text	(MsgInfo	*msginfo,
333
					 const gchar	*dest,
334
					 const gchar	*encoding,
335
					 gboolean	 all_headers);
336

  
332 337
gint	procmsg_concat_partial_messages	(GSList		*mlist,
333 338
					 const gchar	*file);
334 339

  
libsylph/libsylph-0.def
708 708
	folder_get_ui_func2 @ 706
709 709
	folder_call_ui_func2 @ 707
710 710
	export_msgs_to_mbox @ 708
711
	copy_file_stream @ 709
712
	procmsg_save_message_as_text @ 710
src/filesel.c
1 1
/*
2 2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This program is free software; you can redistribute it and/or modify
6 6
 * it under the terms of the GNU General Public License as published by
......
23 23
#include <gtk/gtkversion.h>
24 24
#include <gtk/gtkfilechooserdialog.h>
25 25
#include <gtk/gtkexpander.h>
26
#include <gtk/gtkcombobox.h>
26 27
#include <gtk/gtkstock.h>
27 28

  
28 29
#ifdef G_OS_WIN32
......
45 46
static GSList *filesel_select_file_full	(const gchar		*title,
46 47
					 const gchar		*file,
47 48
					 GtkFileChooserAction	 action,
48
					 gboolean		 multiple);
49
					 gboolean		 multiple,
50
					 GSList			*types,
51
					 gint			 default_type,
52
					 gint			*selected_type);
49 53

  
50 54
static GtkWidget *filesel_create	(const gchar		*title,
51 55
					 GtkFileChooserAction	 action);
......
74 78
	GSList *list;
75 79
	gchar *selected = NULL;
76 80

  
77
	list = filesel_select_file_full(title, file, action, FALSE);
81
	list = filesel_select_file_full(title, file, action, FALSE, NULL, 0, NULL);
78 82
	if (list) {
79 83
		selected = (gchar *)list->data;
80 84
		slist_free_strings(list->next);
......
87 91
GSList *filesel_select_files(const gchar *title, const gchar *file,
88 92
			     GtkFileChooserAction action)
89 93
{
90
	return filesel_select_file_full(title, file, action, TRUE);
94
	return filesel_select_file_full(title, file, action, TRUE, NULL, 0, NULL);
91 95
}
92 96

  
93 97
static void filesel_change_dir_for_action(GtkFileChooserAction action)
......
155 159

  
156 160
static GSList *filesel_select_file_full(const gchar *title, const gchar *file,
157 161
					GtkFileChooserAction action,
158
					gboolean multiple)
162
					gboolean multiple,
163
					GSList *types,
164
					gint default_type, gint *selected_type)
159 165
{
160 166
	gchar *cwd;
161 167
	GtkWidget *dialog;
162 168
	gchar *prev_dir;
163 169
	static gboolean save_expander_expanded = FALSE;
164 170
	GSList *list = NULL;
171
	GtkWidget *combo = NULL;
165 172

  
166 173
	prev_dir = g_get_current_dir();
167 174

  
......
193 200
	}
194 201
#endif
195 202

  
203
	/* create types combo box */
204
	if (types) {
205
		GSList *cur;
206
		GtkWidget *hbox;
207
		GtkWidget *label;
208

  
209
		hbox = gtk_hbox_new(FALSE, 12);
210
		label = gtk_label_new(_("File type:"));
211
		gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
212

  
213
		combo = gtk_combo_box_new_text();
214
		for (cur = types; cur != NULL; cur = cur->next) {
215
			gtk_combo_box_append_text(GTK_COMBO_BOX(combo), (const gchar *)cur->data);
216
		}
217
		gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
218

  
219
		gtk_widget_show_all(hbox);
220
		gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(dialog), hbox);
221
		gtk_combo_box_set_active(GTK_COMBO_BOX(combo), default_type);
222
	}
223

  
196 224
	gtk_widget_show(dialog);
197 225

  
198 226
	change_dir(prev_dir);
......
230 258

  
231 259
	inc_unlock();
232 260

  
261
	if (combo && selected_type) {
262
		*selected_type = gtk_combo_box_get_active(GTK_COMBO_BOX(combo));
263
	}
264

  
233 265
	if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
234 266
		save_expander_expanded =
235 267
			filesel_save_expander_get_expanded(dialog);
......
264 296
	return filename;
265 297
}
266 298

  
299
gchar *filesel_save_as_type(const gchar *file, GSList *types,
300
			    gint default_type, gint *selected_type)
301
{
302
	GSList *list;
303
	gchar *filename = NULL;
304

  
305
	list = filesel_select_file_full(_("Save as"), file,
306
					GTK_FILE_CHOOSER_ACTION_SAVE, FALSE,
307
					types, default_type, selected_type);
308
	if (list) {
309
		filename = (gchar *)list->data;
310
		slist_free_strings(list->next);
311
	}
312
	g_slist_free(list);
313

  
314
#if !GTK_CHECK_VERSION(2, 8, 0)
315
	if (filename && is_file_exist(filename)) {
316
		AlertValue aval;
317

  
318
		aval = alertpanel(_("Overwrite existing file"),
319
				  _("The file already exists. Do you want to replace it?"),
320
				  GTK_STOCK_YES, GTK_STOCK_NO, NULL);
321
		if (G_ALERTDEFAULT != aval) {
322
			g_free(filename);
323
			filename = NULL;
324
		}
325
	}
326
#endif
327

  
328
	return filename;
329
}
330

  
267 331
gchar *filesel_select_dir(const gchar *dir)
268 332
{
269 333
	GSList *list;
......
271 335

  
272 336
	list = filesel_select_file_full(_("Select folder"), dir,
273 337
					GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
274
					FALSE);
338
					FALSE, NULL, 0, NULL);
275 339
	if (list) {
276 340
		selected = (gchar *)list->data;
277 341
		slist_free_strings(list->next);
src/filesel.h
1 1
/*
2 2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This program is free software; you can redistribute it and/or modify
6 6
 * it under the terms of the GNU General Public License as published by
......
31 31
				 GtkFileChooserAction	 action);
32 32

  
33 33
gchar *filesel_save_as		(const gchar		*file);
34
gchar *filesel_save_as_type	(const gchar		*file,
35
				 GSList			*types,
36
				 gint			 default_type,
37
				 gint			*selected_type);
34 38
gchar *filesel_select_dir	(const gchar		*dir);
35 39

  
36 40
#endif /* __FILESEL_H__ */
src/summaryview.c
1 1
/*
2 2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2012 Hiroyuki Yamamoto
3
 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 4
 *
5 5
 * This program is free software; you can redistribute it and/or modify
6 6
 * it under the terms of the GNU General Public License as published by
......
3891 3891
	MsgInfo *msginfo = NULL;
3892 3892
	gchar *filename;
3893 3893
	gchar *src, *dest;
3894
	GSList *types;
3895
	gint selected_type = 0;
3896
	gint result;
3897
	gboolean all_headers;
3894 3898

  
3895 3899
	if (!summaryview->selected) return;
3896 3900
	if (!gtkut_tree_row_reference_get_iter
......
3908 3912
	}
3909 3913
	subst_for_filename(filename);
3910 3914

  
3911
	dest = filesel_save_as(filename);
3915
	types = g_slist_append(NULL, _("Original (EML/RFC 822)"));
3916
	types = g_slist_append(types, _("Text"));
3917
	types = g_slist_append(types, _("Text (UTF-8)"));
3918
	dest = filesel_save_as_type(filename, types, 0, &selected_type);
3919
	g_slist_free(types);
3912 3920

  
3913 3921
	g_free(filename);
3914 3922
	if (!dest)
3915 3923
		return;
3916 3924

  
3917
	src = procmsg_get_message_file(msginfo);
3918
	if (copy_file(src, dest, TRUE) < 0) {
3925
	debug_print("summary_save_as: selected_type: %d\n", selected_type);
3926

  
3927
	all_headers = summaryview->messageview->textview->show_all_headers;
3928

  
3929
	if (selected_type == 1) {
3930
		result = procmsg_save_message_as_text(msginfo, dest, conv_get_locale_charset_str(), all_headers);
3931
	} else if (selected_type == 2) {
3932
		result = procmsg_save_message_as_text(msginfo, dest, NULL, all_headers);
3933
	} else {
3934
		src = procmsg_get_message_file(msginfo);
3935
		result = copy_file(src, dest, TRUE);
3936
		g_free(src);
3937
	}
3938

  
3939
	if (result < 0) {
3919 3940
		gchar *utf8_dest;
3920 3941

  
3921 3942
		utf8_dest = conv_filename_to_utf8(dest);
......
3923 3944
				 g_basename(utf8_dest));
3924 3945
		g_free(utf8_dest);
3925 3946
	}
3926
	g_free(src);
3927 3947

  
3928 3948
	g_free(dest);
3929 3949
}
ChangeLog
1
2013-04-03
2

  
3
	* libsylph/utils.[ch]
4
	  libsylph/procmsg.[ch]
5
	  src/filesel.[ch]
6
	  src/summaryview.c: added the feature to save message as plain text
7
	  (locale or UTF-8 encoding).
8

  
1 9
2013-03-29
2 10

  
3 11
	* version 3.4.0beta3

Also available in: Unified diff