1 /*
2 * e-mail-parser-multipart-encrypted.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 "evolution-config.h"
19
20 #include <glib/gi18n-lib.h>
21
22 #include <libedataserver/libedataserver.h>
23
24 #include "e-mail-formatter-utils.h"
25 #include "e-mail-parser-extension.h"
26 #include "e-mail-part-utils.h"
27
28 typedef EMailParserExtension EMailParserMultipartEncrypted;
29 typedef EMailParserExtensionClass EMailParserMultipartEncryptedClass;
30
31 GType e_mail_parser_multipart_encrypted_get_type (void);
32
33 G_DEFINE_TYPE (
34 EMailParserMultipartEncrypted,
35 e_mail_parser_multipart_encrypted,
36 E_TYPE_MAIL_PARSER_EXTENSION)
37
38 static const gchar *parser_mime_types[] = {
39 "multipart/encrypted",
40 NULL
41 };
42
43 static gboolean
empe_mp_encrypted_parse(EMailParserExtension * extension,EMailParser * parser,CamelMimePart * part,GString * part_id,GCancellable * cancellable,GQueue * out_mail_parts)44 empe_mp_encrypted_parse (EMailParserExtension *extension,
45 EMailParser *parser,
46 CamelMimePart *part,
47 GString *part_id,
48 GCancellable *cancellable,
49 GQueue *out_mail_parts)
50 {
51 CamelCipherContext *context;
52 const gchar *protocol;
53 CamelMimePart *opart;
54 CamelCipherValidity *valid;
55 CamelContentType *content_type;
56 CamelMultipartEncrypted *mpe;
57 GQueue work_queue = G_QUEUE_INIT;
58 GList *head, *link;
59 GError *local_error = NULL;
60 gint len;
61
62 content_type = camel_mime_part_get_content_type (part);
63
64 /* When it's a guessed type, then rather not interpret it as an encrypted message */
65 if (g_strcmp0 (camel_content_type_param (content_type, E_MAIL_PART_X_EVOLUTION_GUESSED), "1") == 0) {
66 e_mail_parser_wrap_as_non_expandable_attachment (parser, part, part_id, out_mail_parts);
67 return TRUE;
68 }
69
70 mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part);
71 if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) {
72 e_mail_parser_error (
73 parser, out_mail_parts,
74 _("Could not parse MIME message. "
75 "Displaying as source."));
76 e_mail_parser_parse_part_as (
77 parser, part, part_id,
78 "application/vnd.evolution/source",
79 cancellable, out_mail_parts);
80
81 return TRUE;
82 }
83
84 /* Currently we only handle RFC2015-style PGP encryption. */
85 protocol = camel_content_type_param (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (mpe)), "protocol");
86 if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
87 e_mail_parser_error (
88 parser, out_mail_parts,
89 _("Unsupported encryption type for multipart/encrypted"));
90 e_mail_parser_parse_part_as (
91 parser, part, part_id, "multipart/mixed",
92 cancellable, out_mail_parts);
93
94 return TRUE;
95 }
96
97 context = camel_gpg_context_new (e_mail_parser_get_session (parser));
98
99 opart = camel_mime_part_new ();
100 valid = camel_cipher_context_decrypt_sync (
101 context, part, opart, cancellable, &local_error);
102
103 e_mail_part_preserve_charset_in_content_type (part, opart);
104
105 if (local_error != NULL) {
106 e_mail_parser_error (
107 parser, out_mail_parts,
108 _("Could not parse PGP/MIME message: %s"),
109 local_error->message);
110 e_mail_parser_parse_part_as (
111 parser, part, part_id, "multipart/mixed",
112 cancellable, out_mail_parts);
113
114 g_object_unref (opart);
115 g_object_unref (context);
116 g_error_free (local_error);
117
118 return TRUE;
119 }
120
121 len = part_id->len;
122 g_string_append (part_id, ".encrypted-pgp");
123
124 g_warn_if_fail (e_mail_parser_parse_part (
125 parser, opart, part_id, cancellable, &work_queue));
126
127 g_string_truncate (part_id, len);
128
129 head = g_queue_peek_head_link (&work_queue);
130
131 /* Update validity of all encrypted sub-parts */
132 for (link = head; link != NULL; link = g_list_next (link)) {
133 EMailPart *mail_part = link->data;
134
135 e_mail_part_update_validity (
136 mail_part, valid,
137 E_MAIL_PART_VALIDITY_ENCRYPTED |
138 E_MAIL_PART_VALIDITY_PGP);
139
140 /* Do not traverse sub-messages */
141 if (g_str_has_suffix (e_mail_part_get_id (mail_part), ".rfc822"))
142 link = e_mail_formatter_find_rfc822_end_iter (link);
143 }
144
145 e_queue_transfer (&work_queue, out_mail_parts);
146
147 /* Add a widget with details about the encryption, but only when
148 * the decrypted part isn't itself secured, in that case it has
149 * created the button itself. */
150 if (!e_mail_part_is_secured (opart)) {
151 EMailPart *mail_part;
152
153 g_string_append (part_id, ".encrypted-pgp.button");
154
155 e_mail_parser_parse_part_as (
156 parser, part, part_id,
157 "application/vnd.evolution.secure-button",
158 cancellable, &work_queue);
159
160 mail_part = g_queue_peek_head (&work_queue);
161
162 if (mail_part != NULL)
163 e_mail_part_update_validity (
164 mail_part, valid,
165 E_MAIL_PART_VALIDITY_ENCRYPTED |
166 E_MAIL_PART_VALIDITY_PGP);
167
168 e_queue_transfer (&work_queue, out_mail_parts);
169
170 g_string_truncate (part_id, len);
171 }
172
173 camel_cipher_validity_free (valid);
174
175 /* TODO: Make sure when we finalize this part, it is zero'd out */
176 g_object_unref (opart);
177 g_object_unref (context);
178
179 return TRUE;
180 }
181
182 static void
e_mail_parser_multipart_encrypted_class_init(EMailParserExtensionClass * class)183 e_mail_parser_multipart_encrypted_class_init (EMailParserExtensionClass *class)
184 {
185 class->mime_types = parser_mime_types;
186 class->priority = G_PRIORITY_LOW;
187 class->parse = empe_mp_encrypted_parse;
188 }
189
190 static void
e_mail_parser_multipart_encrypted_init(EMailParserExtension * extension)191 e_mail_parser_multipart_encrypted_init (EMailParserExtension *extension)
192 {
193 }
194