1 /*
2 * e-mail-formatter-quote.c
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18 #include "e-mail-formatter-quote.h"
19
20 #include <camel/camel.h>
21
22 #include "e-mail-formatter-utils.h"
23 #include "e-mail-part.h"
24 #include "e-mail-part-attachment.h"
25 #include "e-mail-part-utils.h"
26
27 #include <libebackend/libebackend.h>
28 #include <gdk/gdk.h>
29 #include <glib/gi18n.h>
30
31 #define E_MAIL_FORMATTER_QUOTE_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE \
33 ((obj), E_TYPE_MAIL_FORMATTER_QUOTE, EMailFormatterQuotePrivate))
34
35 struct _EMailFormatterQuotePrivate {
36 gchar *credits;
37 EMailFormatterQuoteFlags flags;
38 };
39
40 /* internal formatter extensions */
41 GType e_mail_formatter_quote_headers_get_type (void);
42 GType e_mail_formatter_quote_message_rfc822_get_type (void);
43 GType e_mail_formatter_quote_text_enriched_get_type (void);
44 GType e_mail_formatter_quote_text_html_get_type (void);
45 GType e_mail_formatter_quote_text_plain_get_type (void);
46
47 static gpointer e_mail_formatter_quote_parent_class = 0;
48
49 static void
mail_formatter_quote_run(EMailFormatter * formatter,EMailFormatterContext * context,GOutputStream * stream,GCancellable * cancellable)50 mail_formatter_quote_run (EMailFormatter *formatter,
51 EMailFormatterContext *context,
52 GOutputStream *stream,
53 GCancellable *cancellable)
54 {
55 EMailFormatterQuote *qf;
56 EMailFormatterQuoteContext *qf_context;
57 GQueue queue = G_QUEUE_INIT;
58 GList *head, *link;
59 const gchar *string;
60
61 if (g_cancellable_is_cancelled (cancellable))
62 return;
63
64 qf = E_MAIL_FORMATTER_QUOTE (formatter);
65
66 qf_context = (EMailFormatterQuoteContext *) context;
67 qf_context->qf_flags = qf->priv->flags;
68
69 if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_NO_FORMATTING) != 0)
70 context->flags |= E_MAIL_FORMATTER_HEADER_FLAG_NO_FORMATTING;
71
72 g_seekable_seek (
73 G_SEEKABLE (stream),
74 0, G_SEEK_SET, NULL, NULL);
75
76 e_mail_part_list_queue_parts (context->part_list, NULL, &queue);
77
78 head = g_queue_peek_head_link (&queue);
79
80 for (link = head; link != NULL; link = g_list_next (link)) {
81 EMailPart *part = E_MAIL_PART (link->data);
82 const gchar *mime_type;
83
84 if (e_mail_part_id_has_suffix (part, ".headers") &&
85 !(qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_HEADERS)) {
86 continue;
87 }
88
89 if (e_mail_part_id_has_suffix (part, ".rfc822")) {
90 link = e_mail_formatter_find_rfc822_end_iter (link);
91 continue;
92 }
93
94 if (part->is_hidden)
95 continue;
96
97 if (e_mail_part_get_is_attachment (part))
98 continue;
99
100 mime_type = e_mail_part_get_mime_type (part);
101
102 /* Skip error messages in the quoted part */
103 if (g_strcmp0 (mime_type, "application/vnd.evolution.error") == 0)
104 continue;
105
106 e_mail_formatter_format_as (
107 formatter, context, part, stream,
108 mime_type, cancellable);
109 }
110
111 while (!g_queue_is_empty (&queue))
112 g_object_unref (g_queue_pop_head (&queue));
113
114 /* Before we were inserting the BR elements and the credits in front of
115 * the actual HTML code of the message. But this was wrong as when WebKit
116 * was loading the given HTML code that looked like
117 * <br>CREDITS<html>MESSAGE_CODE</html> WebKit parsed it like
118 * <html><br>CREDITS</html><html>MESSAGE_CODE</html>. As no elements are
119 * allowed outside of the HTML root element WebKit wrapped them into
120 * another HTML root element. Afterwards the first root element was
121 * treated as the primary one and all the elements from the second's root
122 * HEAD and BODY elements were moved to the first one.
123 * Thus the HTML that was loaded into composer contained the i.e. META
124 * or STYLE definitions in the body.
125 * So if we want to put something into the message we have to put it into
126 * the special span element and it will be moved to body in EHTMLEditorView */
127 if (qf->priv->credits && *qf->priv->credits) {
128 gchar *credits = g_markup_printf_escaped (
129 "<span class=\"-x-evo-to-body\" data-credits=\"%s\"></span>",
130 qf->priv->credits);
131 g_output_stream_write_all (
132 stream, credits, strlen (credits), NULL, cancellable, NULL);
133 g_free (credits);
134 }
135
136 /* If we want to cite the message we have to append the special span element
137 * after the message and cite it in EHTMLEditorView because of reasons
138 * mentioned above */
139 if (qf->priv->flags & E_MAIL_FORMATTER_QUOTE_FLAG_CITE) {
140 string = "<span class=\"-x-evo-cite-body\"></span>";
141 g_output_stream_write_all (
142 stream, string, strlen (string), NULL, cancellable, NULL);
143 }
144 }
145
146 static void
e_mail_formatter_quote_init(EMailFormatterQuote * formatter)147 e_mail_formatter_quote_init (EMailFormatterQuote *formatter)
148 {
149 formatter->priv = E_MAIL_FORMATTER_QUOTE_GET_PRIVATE (formatter);
150 }
151
152 static void
e_mail_formatter_quote_finalize(GObject * object)153 e_mail_formatter_quote_finalize (GObject *object)
154 {
155 EMailFormatterQuote *formatter;
156
157 formatter = E_MAIL_FORMATTER_QUOTE (object);
158
159 g_free (formatter->priv->credits);
160 formatter->priv->credits = NULL;
161
162 /* Chain up to parent's finalize() */
163 G_OBJECT_CLASS (e_mail_formatter_quote_parent_class)->finalize (object);
164 }
165
166 static void
e_mail_formatter_quote_base_init(EMailFormatterQuoteClass * class)167 e_mail_formatter_quote_base_init (EMailFormatterQuoteClass *class)
168 {
169 /* Register internal extensions. */
170 g_type_ensure (e_mail_formatter_quote_headers_get_type ());
171 g_type_ensure (e_mail_formatter_quote_message_rfc822_get_type ());
172 g_type_ensure (e_mail_formatter_quote_text_enriched_get_type ());
173 g_type_ensure (e_mail_formatter_quote_text_html_get_type ());
174 g_type_ensure (e_mail_formatter_quote_text_plain_get_type ());
175
176 e_mail_formatter_extension_registry_load (
177 E_MAIL_FORMATTER_CLASS (class)->extension_registry,
178 E_TYPE_MAIL_FORMATTER_QUOTE_EXTENSION);
179
180 E_MAIL_FORMATTER_CLASS (class)->text_html_flags =
181 CAMEL_MIME_FILTER_TOHTML_PRE |
182 CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
183 CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
184 }
185
186 static void
e_mail_formatter_quote_class_init(EMailFormatterQuoteClass * class)187 e_mail_formatter_quote_class_init (EMailFormatterQuoteClass *class)
188 {
189 GObjectClass *object_class;
190 EMailFormatterClass *formatter_class;
191
192 e_mail_formatter_quote_parent_class = g_type_class_peek_parent (class);
193 g_type_class_add_private (class, sizeof (EMailFormatterQuotePrivate));
194
195 formatter_class = E_MAIL_FORMATTER_CLASS (class);
196 formatter_class->context_size = sizeof (EMailFormatterQuoteContext);
197 formatter_class->run = mail_formatter_quote_run;
198
199 object_class = G_OBJECT_CLASS (class);
200 object_class->finalize = e_mail_formatter_quote_finalize;
201 }
202
203 GType
e_mail_formatter_quote_get_type(void)204 e_mail_formatter_quote_get_type (void)
205 {
206 static GType type = 0;
207
208 if (G_UNLIKELY (type == 0)) {
209 const GTypeInfo type_info = {
210 sizeof (EMailFormatterClass),
211 (GBaseInitFunc) e_mail_formatter_quote_base_init,
212 (GBaseFinalizeFunc) NULL,
213 (GClassInitFunc) e_mail_formatter_quote_class_init,
214 (GClassFinalizeFunc) NULL,
215 NULL, /* class_data */
216 sizeof (EMailFormatterQuote),
217 0, /* n_preallocs */
218 (GInstanceInitFunc) e_mail_formatter_quote_init,
219 NULL /* value_table */
220 };
221
222 type = g_type_register_static (
223 E_TYPE_MAIL_FORMATTER,
224 "EMailFormatterQuote", &type_info, 0);
225 }
226
227 return type;
228 }
229
230 EMailFormatter *
e_mail_formatter_quote_new(const gchar * credits,EMailFormatterQuoteFlags flags)231 e_mail_formatter_quote_new (const gchar *credits,
232 EMailFormatterQuoteFlags flags)
233 {
234 EMailFormatterQuote *formatter;
235 formatter = g_object_new (E_TYPE_MAIL_FORMATTER_QUOTE, NULL);
236
237 formatter->priv->credits = g_strdup (credits);
238 formatter->priv->flags = flags;
239
240 return (EMailFormatter *) formatter;
241 }
242
243 /* ------------------------------------------------------------------------- */
244
G_DEFINE_ABSTRACT_TYPE(EMailFormatterQuoteExtension,e_mail_formatter_quote_extension,E_TYPE_MAIL_FORMATTER_EXTENSION)245 G_DEFINE_ABSTRACT_TYPE (
246 EMailFormatterQuoteExtension,
247 e_mail_formatter_quote_extension,
248 E_TYPE_MAIL_FORMATTER_EXTENSION)
249
250 static void
251 e_mail_formatter_quote_extension_class_init (EMailFormatterQuoteExtensionClass *class)
252 {
253 }
254
255 static void
e_mail_formatter_quote_extension_init(EMailFormatterQuoteExtension * extension)256 e_mail_formatter_quote_extension_init (EMailFormatterQuoteExtension *extension)
257 {
258 }
259
260