"Fossies" - the Fresh Open Source Software Archive 
Member "evolution-mapi-3.46.1/src/libexchangemapi/e-mapi-mail-utils.c" (2 Dec 2022, 55333 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "e-mapi-mail-utils.c" see the
Fossies "Dox" file reference documentation.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
15 *
16 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
17 *
18 */
19
20 #include "evolution-mapi-config.h"
21
22 #include <camel/camel.h>
23 #include <libecal/libecal.h>
24
25 #include "e-mapi-defs.h"
26 #include "e-mapi-utils.h"
27 #include "e-mapi-book-utils.h"
28 #include "e-mapi-cal-utils.h"
29 #include "e-mapi-mail-utils.h"
30
31 #define STREAM_SIZE 4000
32
33 void
34 e_mapi_mail_utils_decode_email_address (EMapiConnection *conn,
35 struct mapi_SPropValue_array *properties,
36 const uint32_t *name_proptags,
37 guint name_proptags_len,
38 const uint32_t *smtp_proptags,
39 guint smtp_proptags_len,
40 uint32_t email_type_proptag,
41 uint32_t email_proptag,
42 gchar **name,
43 gchar **email)
44 {
45 gint ii;
46 const gchar *cname = NULL, *cemail = NULL;
47 const gchar *addr_type, *email_addr;
48
49 g_return_if_fail (conn != NULL);
50 g_return_if_fail (properties != NULL);
51 g_return_if_fail (name_proptags_len == 0 || name_proptags != NULL);
52 g_return_if_fail (smtp_proptags_len == 0 || smtp_proptags != NULL);
53 g_return_if_fail (name != NULL);
54 g_return_if_fail (email != NULL);
55
56 *name = NULL;
57 *email = NULL;
58
59 for (ii = 0; ii < name_proptags_len && !cname; ii++) {
60 cname = e_mapi_util_find_array_propval (properties, name_proptags[ii]);
61 }
62
63 addr_type = e_mapi_util_find_array_propval (properties, email_type_proptag);
64 email_addr = e_mapi_util_find_array_propval (properties, email_proptag);
65
66 if (addr_type && g_ascii_strcasecmp (addr_type, "SMTP") == 0)
67 cemail = email_addr;
68
69 for (ii = 0; ii < smtp_proptags_len && !cemail; ii++) {
70 cemail = e_mapi_util_find_array_propval (properties, smtp_proptags[ii]);
71 }
72
73 if (!cemail && addr_type && g_ascii_strcasecmp (addr_type, "EX") == 0 && email_addr) {
74 *email = e_mapi_connection_ex_to_smtp (conn, email_addr, name, NULL, NULL);
75 }
76
77 if (!*email) {
78 *name = g_strdup (cname);
79 *email = g_strdup (cemail);
80 }
81 }
82
83 void
84 e_mapi_mail_utils_decode_email_address1 (EMapiConnection *conn,
85 struct mapi_SPropValue_array *properties,
86 uint32_t name_proptag,
87 uint32_t email_proptag,
88 uint32_t email_type_proptag,
89 gchar **name,
90 gchar **email)
91 {
92 uint32_t names[1];
93
94 names[0] = name_proptag;
95
96 e_mapi_mail_utils_decode_email_address (conn, properties, names, 1, NULL, 0, email_type_proptag, email_proptag, name, email);
97 }
98
99 void
100 e_mapi_mail_utils_decode_recipients (EMapiConnection *conn,
101 EMapiRecipient *recipients,
102 CamelAddress *to_addr,
103 CamelAddress *cc_addr,
104 CamelAddress *bcc_addr)
105 {
106 const uint32_t name_proptags[] = {
107 PROP_TAG (PT_UNICODE, 0x6001), /* PidTagNickname for Recipients table */
108 PidTagNickname,
109 PidTagDisplayName,
110 PidTagRecipientDisplayName,
111 PidTagAddressBookDisplayNamePrintable
112 };
113
114 const uint32_t email_proptags[] = {
115 PidTagSmtpAddress
116 };
117
118 EMapiRecipient *recipient;
119
120 g_return_if_fail (conn != NULL);
121 g_return_if_fail (to_addr != NULL);
122 g_return_if_fail (cc_addr != NULL);
123 g_return_if_fail (bcc_addr != NULL);
124
125 for (recipient = recipients; recipient; recipient = recipient->next) {
126 const uint32_t *recip_type = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientType);
127 gchar *name = NULL, *email = NULL;
128 CamelAddress *addr = NULL;
129
130 if (!recip_type)
131 continue;
132
133 switch (*recip_type) {
134 case MAPI_TO:
135 addr = to_addr;
136 break;
137 case MAPI_CC:
138 addr = cc_addr;
139 break;
140 case MAPI_BCC:
141 addr = bcc_addr;
142 break;
143 default:
144 break;
145 }
146
147 if (!addr)
148 continue;
149
150 e_mapi_mail_utils_decode_email_address (conn, &recipient->properties,
151 name_proptags, G_N_ELEMENTS (name_proptags),
152 email_proptags, G_N_ELEMENTS (email_proptags),
153 PidTagAddressType, PidTagEmailAddress,
154 &name, &email);
155
156 camel_internet_address_add (CAMEL_INTERNET_ADDRESS (addr), name, email ? email : "");
157
158 g_free (name);
159 g_free (email);
160 }
161 }
162
163 static void
164 build_body_part_content (CamelMimePart *part, EMapiObject *object, uint32_t proptag)
165 {
166 uint64_t str_cb = 0;
167 const uint8_t *str_lpb = NULL;
168
169 g_return_if_fail (part != NULL);
170 g_return_if_fail (object != NULL);
171 g_return_if_fail (proptag == PidTagHtml || proptag == PidTagBody);
172
173 camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_8BIT);
174
175 if (e_mapi_object_get_bin_prop (object, proptag, &str_cb, &str_lpb)) {
176 const gchar *type = NULL;
177 gchar *buff = NULL, *in_utf8;
178 const uint32_t *pcpid = e_mapi_util_find_array_propval (&object->properties, PidTagInternetCodepage);
179
180 if (proptag == PidTagBody) {
181 type = "text/plain";
182 } else {
183 type = "text/html";
184 }
185
186 if (!e_mapi_util_find_array_proptag (&object->properties, proptag)) {
187 EMapiStreamedProp *stream = e_mapi_object_get_streamed (object, proptag);
188 if (stream)
189 proptag = stream->proptag;
190 } else {
191 proptag = e_mapi_util_find_array_proptag (&object->properties, proptag);
192 }
193
194 if (pcpid && *pcpid && (proptag & 0xFFFF) != PT_UNICODE) {
195 uint32_t cpid = *pcpid;
196
197 if (cpid == 20127)
198 buff = g_strdup_printf ("%s; charset=\"us-ascii\"", type);
199 else if (cpid == 20866)
200 buff = g_strdup_printf ("%s; charset=\"koi8-r\"", type);
201 else if (cpid >= 28591 && cpid <= 28599)
202 buff = g_strdup_printf ("%s; charset=\"ISO-8859-%d\"", type, cpid % 10);
203 else if (cpid == 28603)
204 buff = g_strdup_printf ("%s; charset=\"ISO-8859-13\"", type);
205 else if (cpid == 28605)
206 buff = g_strdup_printf ("%s; charset=\"ISO-8859-15\"", type);
207 else if (cpid == 65000)
208 buff = g_strdup_printf ("%s; charset=\"UTF-7\"", type);
209 else if (cpid == 65001)
210 buff = g_strdup_printf ("%s; charset=\"UTF-8\"", type);
211 else
212 buff = g_strdup_printf ("%s; charset=\"CP%d\"", type, cpid);
213 type = buff;
214 }
215
216 in_utf8 = NULL;
217
218 if (proptag == PidTagHtml) {
219 if (e_mapi_utils_ensure_utf8_string (proptag, pcpid, str_lpb, str_cb, &in_utf8))
220 camel_mime_part_set_content (part, in_utf8, strlen (in_utf8), type);
221 else
222 camel_mime_part_set_content (part, (const gchar *) str_lpb, str_cb, type);
223
224 } else {
225 if (e_mapi_utils_ensure_utf8_string (proptag, pcpid, str_lpb, str_cb, &in_utf8)) {
226 str_lpb = (const uint8_t *) in_utf8;
227 str_cb = strlen (in_utf8);
228 }
229
230 /* cannot set an empty content */
231 if (!str_cb)
232 camel_mime_part_set_content (part, " ", 1, type);
233 else
234 camel_mime_part_set_content (part, (const gchar *) str_lpb, str_cb, type);
235 }
236
237 g_free (in_utf8);
238 g_free (buff);
239 } else
240 camel_mime_part_set_content (part, " ", 1, "text/plain");
241 }
242
243 static gboolean
244 is_apple_attach (EMapiAttachment *attach, guint32 *data_len, guint32 *resource_len)
245 {
246 gboolean is_apple = FALSE;
247 uint64_t enc_cb = 0;
248 const uint8_t *enc_lpb = NULL;
249 guint8 apple_enc_magic[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x14, 0x03, 0x0B, 0x01 };
250
251 if (e_mapi_attachment_get_bin_prop (attach, PidTagAttachEncoding, &enc_cb, &enc_lpb) && enc_cb == G_N_ELEMENTS (apple_enc_magic)) {
252 gint idx;
253
254 is_apple = TRUE;
255 for (idx = 0; idx < enc_cb && is_apple; idx++) {
256 is_apple = apple_enc_magic[idx] == enc_lpb[idx];
257 }
258 }
259
260 if (is_apple) {
261 /* check boundaries too */
262 uint64_t data_cb = 0;
263 const uint8_t *data_lpb = NULL;
264
265 is_apple = e_mapi_attachment_get_bin_prop (attach, PidTagAttachDataBinary, &data_cb, &data_lpb) && data_lpb && data_cb > 128;
266
267 if (is_apple) {
268 const guint8 *bin = data_lpb;
269
270 /* in big-endian format */
271 *data_len = (bin[83] << 24) | (bin[84] << 16) | (bin[85] << 8) | (bin[86]);
272 *resource_len = (bin[87] << 24) | (bin[88] << 16) | (bin[89] << 8) | (bin[90]);
273
274 /* +/- mod 128 (but the first 128 is a header length) */
275 is_apple = 128 + *data_len + *resource_len <= data_cb && bin[1] < 64;
276 }
277 }
278
279 return is_apple;
280 }
281
282 typedef struct {
283 GHashTable *tzids;
284 ICalComponent *icomp;
285 } ForeachTZIDData;
286
287 static void
288 add_timezones_cb (ICalParameter *param,
289 gpointer data)
290 {
291 ForeachTZIDData *tz_data = data;
292 const gchar *tzid;
293 ICalTimezone *zone = NULL;
294 ICalComponent *vtimezone_comp;
295
296 /* Get the TZID string from the parameter. */
297 tzid = i_cal_parameter_get_tzid (param);
298 if (!tzid || g_hash_table_lookup (tz_data->tzids, tzid))
299 return;
300
301 /* Look for the timezone */
302 zone = i_cal_timezone_get_builtin_timezone_from_tzid (tzid);
303 if (!zone)
304 return;
305
306 /* Convert it to a string and add it to the hash. */
307 vtimezone_comp = i_cal_timezone_get_component (zone);
308 if (!vtimezone_comp)
309 return;
310
311 i_cal_component_take_component (tz_data->icomp, i_cal_component_clone (vtimezone_comp));
312
313 g_hash_table_insert (tz_data->tzids, g_strdup (tzid), GINT_TO_POINTER (1));
314 }
315
316 static gchar *
317 build_ical_string (EMapiConnection *conn,
318 EMapiObject *object,
319 const gchar *msg_class)
320 {
321 gchar *ical_string = NULL, *use_uid;
322 ICalComponentKind kind = I_CAL_NO_COMPONENT;
323 ICalPropertyMethod method = I_CAL_METHOD_NONE;
324 const uint64_t *pmid;
325 ECalComponent *comp;
326 ICalComponent *icomp;
327 GSList *detached_components = NULL, *iter;
328
329 g_return_val_if_fail (conn != NULL, NULL);
330 g_return_val_if_fail (object != NULL, NULL);
331 g_return_val_if_fail (msg_class != NULL, NULL);
332
333 if (g_ascii_strcasecmp (msg_class, IPM_SCHEDULE_MEETING_REQUEST) == 0) {
334 method = I_CAL_METHOD_REQUEST;
335 kind = I_CAL_VEVENT_COMPONENT;
336 } else if (g_ascii_strcasecmp (msg_class, IPM_SCHEDULE_MEETING_CANCELED) == 0) {
337 method = I_CAL_METHOD_CANCEL;
338 kind = I_CAL_VEVENT_COMPONENT;
339 } else if (g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_RESP_PREFIX)) {
340 method = I_CAL_METHOD_REPLY;
341 kind = I_CAL_VEVENT_COMPONENT;
342 } else if (g_ascii_strcasecmp (msg_class, IPM_APPOINTMENT) == 0) {
343 method = I_CAL_METHOD_NONE;
344 kind = I_CAL_VEVENT_COMPONENT;
345 } else if (g_ascii_strcasecmp (msg_class, IPM_TASK) == 0) {
346 method = I_CAL_METHOD_NONE;
347 kind = I_CAL_VTODO_COMPONENT;
348 } else if (g_ascii_strcasecmp (msg_class, IPM_STICKYNOTE) == 0) {
349 method = I_CAL_METHOD_NONE;
350 kind = I_CAL_VJOURNAL_COMPONENT;
351 } else {
352 return NULL;
353 }
354
355 pmid = e_mapi_util_find_array_propval (&object->properties, PidTagMid);
356 if (pmid)
357 use_uid = e_mapi_util_mapi_id_to_string (*pmid);
358 else
359 use_uid = e_util_generate_uid ();
360
361 comp = e_mapi_cal_util_object_to_comp (conn, object, kind, method == I_CAL_METHOD_REPLY, use_uid, &detached_components);
362
363 g_free (use_uid);
364
365 if (!comp)
366 return NULL;
367
368 if (method != I_CAL_METHOD_NONE || detached_components) {
369 ForeachTZIDData tz_data;
370 ICalComponent *clone;
371
372 clone = i_cal_component_clone (e_cal_component_get_icalcomponent (comp));
373
374 icomp = e_cal_util_new_top_level ();
375 if (method != I_CAL_METHOD_NONE)
376 i_cal_component_set_method (icomp, method);
377
378 tz_data.tzids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
379 tz_data.icomp = icomp;
380
381 /* Add timezones first */
382 i_cal_component_foreach_tzid (clone, add_timezones_cb, &tz_data);
383
384 g_hash_table_destroy (tz_data.tzids);
385
386 /* Then the components */
387 i_cal_component_take_component (icomp, clone);
388 for (iter = detached_components; iter; iter = g_slist_next (iter)) {
389 i_cal_component_take_component (icomp,
390 i_cal_component_clone (e_cal_component_get_icalcomponent (iter->data)));
391 }
392
393 ical_string = i_cal_component_as_ical_string (icomp);
394
395 g_object_unref (icomp);
396 } else {
397 ical_string = e_cal_component_get_as_string (comp);
398 }
399
400 g_slist_free_full (detached_components, g_object_unref);
401 g_object_unref (comp);
402
403 return ical_string;
404 }
405
406 static void
407 classify_attachments (EMapiConnection *conn,
408 EMapiAttachment *attachments,
409 gboolean can_inline_attachments,
410 const gchar *msg_class,
411 GSList **inline_attachments,
412 GSList **noninline_attachments)
413 {
414 EMapiAttachment *attach;
415 gboolean is_smime = msg_class && strstr (msg_class, ".SMIME.") > msg_class;
416
417 g_return_if_fail (inline_attachments != NULL);
418 g_return_if_fail (noninline_attachments != NULL);
419
420 for (attach = attachments; attach != NULL; attach = attach->next) {
421 const gchar *filename, *mime_type, *content_id = NULL;
422 CamelContentType *content_type;
423 CamelMimePart *part;
424 const uint32_t *ui32;
425 uint64_t data_cb = 0;
426 const uint8_t *data_lpb = NULL;
427 gboolean is_apple, is_message;
428 guint32 apple_data_len = 0, apple_resource_len = 0;
429
430 if (!e_mapi_attachment_get_bin_prop (attach, PidTagAttachDataBinary, &data_cb, &data_lpb) && !attach->embedded_object) {
431 g_debug ("%s: Skipping attachment without data and without embedded object", G_STRFUNC);
432 continue;
433 }
434
435 is_apple = is_apple_attach (attach, &apple_data_len, &apple_resource_len);
436
437 /* Content-Type */
438 ui32 = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachMethod);
439 is_message = ui32 && *ui32 == ATTACH_EMBEDDED_MSG;
440 if (is_message) {
441 mime_type = "message/rfc822";
442 } else {
443 mime_type = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachMimeTag);
444 if (!mime_type)
445 mime_type = "application/octet-stream";
446 is_message = g_ascii_strcasecmp (mime_type, "message/rfc822") == 0;
447 }
448
449 if (is_apple) {
450 mime_type = "application/applefile";
451 } else if (strstr (mime_type, "apple") != NULL) {
452 mime_type = "application/octet-stream";
453 }
454
455 part = camel_mime_part_new ();
456
457 filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachLongFilename);
458 if (!filename || !*filename)
459 filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachFilename);
460 camel_mime_part_set_filename (part, filename);
461 camel_content_type_set_param (camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (part)), "name", filename);
462
463 if (is_apple) {
464 CamelMultipart *mp;
465 gchar *apple_filename;
466 uint64_t mac_info_cb = 0;
467 const uint8_t *mac_info_lpb = NULL;
468
469 mp = camel_multipart_new ();
470 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "multipart/appledouble");
471 camel_multipart_set_boundary (mp, NULL);
472
473 camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
474
475 if (e_mapi_attachment_get_bin_prop (attach, PidNameAttachmentMacInfo, &mac_info_cb, &mac_info_lpb) && mac_info_lpb && mac_info_cb > 0) {
476 camel_mime_part_set_content (part, (const gchar *) mac_info_lpb, mac_info_cb, mime_type);
477 } else {
478 /* RFC 1740 */
479 guint8 header[] = {
480 0x00, 0x05, 0x16, 0x07, /* magic */
481 0x00, 0x02, 0x00, 0x00, /* version */
482 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* filler */
483 0x00, 0x01, /* number of entries */
484 0x00, 0x00, 0x00, 0x02, /* entry ID - resource fork */
485 0x00, 0x00, 0x00, 0x26, /* entry offset - 38th byte*/
486 0x00, 0x00, 0x00, 0x00 /* entry length */
487 };
488
489 GByteArray *arr = g_byte_array_sized_new (apple_resource_len + G_N_ELEMENTS (header));
490
491 header[34] = (apple_resource_len >> 24) & 0xFF;
492 header[35] = (apple_resource_len >> 16) & 0xFF;
493 header[36] = (apple_resource_len >> 8) & 0xFF;
494 header[37] = (apple_resource_len ) & 0xFF;
495
496 g_byte_array_append (arr, header, G_N_ELEMENTS (header));
497 g_byte_array_append (arr, data_lpb + 128 + apple_data_len + (apple_data_len % 128), apple_resource_len);
498
499 camel_mime_part_set_content (part, (const gchar *) arr->data, arr->len, mime_type);
500
501 g_byte_array_free (arr, TRUE);
502 }
503
504 camel_multipart_add_part (mp, part);
505 g_object_unref (part);
506
507 part = camel_mime_part_new ();
508
509 apple_filename = g_strndup ((const gchar *) data_lpb + 2, data_lpb[1]);
510 camel_mime_part_set_filename (part, (apple_filename && *apple_filename) ? apple_filename : filename);
511 g_free (apple_filename);
512
513 mime_type = e_mapi_util_find_array_propval (&attach->properties, PidNameAttachmentMacContentType);
514 if (!mime_type)
515 mime_type = "application/octet-stream";
516
517 camel_mime_part_set_content (part, (const gchar *) data_lpb + 128, apple_data_len, mime_type);
518 camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
519 camel_multipart_add_part (mp, part);
520 g_object_unref (part);
521
522 part = camel_mime_part_new ();
523 camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (mp));
524 g_object_unref (mp);
525 } else if (is_smime) {
526 CamelMimeParser *parser;
527 CamelStream *mem;
528
529 mem = camel_stream_mem_new ();
530 camel_stream_write (mem, (const gchar *) data_lpb, data_cb, NULL, NULL);
531 g_seekable_seek (G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL);
532
533 parser = camel_mime_parser_new ();
534 camel_mime_parser_scan_from (parser, FALSE);
535 camel_mime_parser_scan_pre_from (parser, FALSE);
536 camel_mime_parser_init_with_stream (parser, mem, NULL);
537
538 if (camel_mime_parser_step (parser, NULL, NULL) == CAMEL_MIME_PARSER_STATE_HEADER
539 && camel_mime_parser_content_type (parser) != NULL) {
540 g_object_unref (part);
541 part = camel_mime_part_new ();
542
543 camel_data_wrapper_set_mime_type_field (CAMEL_DATA_WRAPPER (part), camel_mime_parser_content_type (parser));
544 camel_mime_part_construct_content_from_parser (part, parser, NULL, NULL);
545 } else {
546 is_smime = FALSE;
547 }
548
549 g_object_unref (parser);
550 g_object_unref (mem);
551 }
552
553 if (!is_smime && !is_apple) {
554 if (ui32 && *ui32 == ATTACH_EMBEDDED_MSG && attach->embedded_object) {
555 const gchar *embedded_msg_class = e_mapi_util_find_array_propval (&attach->embedded_object->properties, PidTagMessageClass);
556 gboolean fallback = FALSE;
557
558 if (embedded_msg_class &&
559 (g_ascii_strcasecmp (embedded_msg_class, IPM_CONTACT) == 0 ||
560 g_ascii_strcasecmp (embedded_msg_class, IPM_DISTLIST) == 0)) {
561 EContact *contact = e_mapi_book_utils_contact_from_object (conn, attach->embedded_object, NULL);
562
563 if (contact) {
564 gchar *str;
565
566 if (!e_contact_get_const (contact, E_CONTACT_UID))
567 e_contact_set (contact, E_CONTACT_UID, "");
568
569 str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
570 if (str) {
571 camel_mime_part_set_content (part, str, strlen (str), "text/x-vcard");
572
573 g_free (str);
574 } else {
575 fallback = TRUE;
576 }
577
578 g_object_unref (contact);
579 } else {
580 fallback = TRUE;
581 }
582 } else if (embedded_msg_class &&
583 (g_ascii_strcasecmp (embedded_msg_class, IPM_APPOINTMENT) == 0 ||
584 g_ascii_strcasecmp (embedded_msg_class, IPM_TASK) == 0 ||
585 g_ascii_strcasecmp (embedded_msg_class, IPM_STICKYNOTE) == 0)) {
586 gchar *str = build_ical_string (conn, attach->embedded_object, embedded_msg_class);
587
588 if (str) {
589 camel_mime_part_set_content (part, str, strlen (str), "text/calendar");
590
591 g_free (str);
592 } else {
593 fallback = TRUE;
594 }
595 } else {
596 fallback = TRUE;
597 }
598
599 if (fallback) {
600 CamelMimeMessage *embedded_msg;
601
602 embedded_msg = e_mapi_mail_utils_object_to_message (conn, attach->embedded_object);
603 if (embedded_msg) {
604 CamelStream *mem;
605 GByteArray *data;
606
607 data = g_byte_array_new ();
608
609 mem = camel_stream_mem_new ();
610 camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (mem), data);
611 camel_data_wrapper_write_to_stream_sync (
612 CAMEL_DATA_WRAPPER (embedded_msg), mem, NULL, NULL);
613
614 g_object_unref (mem);
615 g_object_unref (embedded_msg);
616
617 camel_mime_part_set_content (part, (const gchar *) data->data, data->len, mime_type);
618
619 g_byte_array_free (data, TRUE);
620 } else {
621 camel_mime_part_set_content (part, (const gchar *) data_lpb, data_cb, mime_type);
622 }
623 }
624 } else {
625 camel_mime_part_set_content (part, (const gchar *) data_lpb, data_cb, mime_type);
626 }
627
628 content_type = camel_mime_part_get_content_type (part);
629 if (content_type && camel_content_type_is (content_type, "text", "*"))
630 camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_QUOTEDPRINTABLE);
631 else if (!is_message)
632 camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64);
633 }
634
635 /* Content-Disposition */
636 ui32 = e_mapi_util_find_array_propval (&attach->properties, PidTagRenderingPosition);
637 if (ui32 && *ui32 != 0xFFFFFFFF)
638 camel_mime_part_set_disposition (part, "attachment; inline");
639 else
640 camel_mime_part_set_disposition (part, "attachment");
641
642 /* Content-ID */
643 content_id = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachContentId);
644 if (content_id)
645 camel_mime_part_set_content_id (part, content_id);
646
647 if (content_id && !is_apple && !is_smime && can_inline_attachments) {
648 *inline_attachments = g_slist_append (*inline_attachments, part);
649 } else
650 *noninline_attachments = g_slist_append (*noninline_attachments, part);
651 }
652 }
653
654 static void
655 add_multipart_attachments (CamelMultipart *multipart, GSList *attachments)
656 {
657 CamelMimePart *part;
658 while (attachments) {
659 part = attachments->data;
660 camel_multipart_add_part (multipart, part);
661 attachments = attachments->next;
662 }
663 }
664
665 static CamelMultipart *
666 build_multipart_related (EMapiObject *object, GSList *inline_attachments)
667 {
668 CamelMimePart *part;
669 CamelMultipart *m_related = camel_multipart_new ();
670 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_related), "multipart/related");
671 camel_multipart_set_boundary (m_related, NULL);
672
673 if (e_mapi_object_contains_prop (object, PidTagHtml)) {
674 part = camel_mime_part_new ();
675 build_body_part_content (part, object, PidTagHtml);
676 camel_multipart_add_part (m_related, part);
677 g_object_unref (part);
678 } else if (e_mapi_object_contains_prop (object, PidTagBody)) {
679 part = camel_mime_part_new ();
680 build_body_part_content (part, object, PidTagBody);
681 camel_multipart_add_part (m_related, part);
682 g_object_unref (part);
683 }
684
685 add_multipart_attachments (m_related, inline_attachments);
686
687 return m_related;
688 }
689
690 static CamelMultipart *
691 build_multipart_alternative (EMapiObject *object, GSList *inline_attachments)
692 {
693 CamelMimePart *part;
694 CamelMultipart *m_alternative;
695
696 m_alternative = camel_multipart_new ();
697 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_alternative), "multipart/alternative");
698 camel_multipart_set_boundary (m_alternative, NULL);
699
700 if (e_mapi_object_contains_prop (object, PidTagBody)) {
701 part = camel_mime_part_new ();
702 build_body_part_content (part, object, PidTagBody);
703 camel_multipart_add_part (m_alternative, part);
704 g_object_unref (part);
705 }
706
707 if (e_mapi_object_contains_prop (object, PidTagHtml)) {
708 part = camel_mime_part_new ();
709 if (inline_attachments) {
710 CamelMultipart *m_related;
711
712 m_related = build_multipart_related (object, inline_attachments);
713 camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (m_related));
714 g_object_unref (m_related);
715 } else {
716 build_body_part_content (part, object, PidTagHtml);
717 }
718 camel_multipart_add_part (m_alternative, part);
719 g_object_unref (part);
720 }
721
722 return m_alternative;
723 }
724
725 static CamelMultipart *
726 build_multipart_mixed (CamelMultipart *content, GSList *attachments)
727 {
728 CamelMultipart *m_mixed = camel_multipart_new ();
729 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (m_mixed), "multipart/mixed");
730 camel_multipart_set_boundary (m_mixed, NULL);
731
732 if (content) {
733 CamelMimePart *part = camel_mime_part_new ();
734
735 camel_medium_set_content (CAMEL_MEDIUM (part), CAMEL_DATA_WRAPPER (content));
736 camel_multipart_add_part (m_mixed, part);
737
738 g_object_unref (part);
739 g_object_unref (content);
740 }
741
742 add_multipart_attachments (m_mixed, attachments);
743
744 return m_mixed;
745 }
746
747 CamelMimeMessage *
748 e_mapi_mail_utils_object_to_message (EMapiConnection *conn, /* const */ EMapiObject *object)
749 {
750 CamelMimeMessage *msg;
751 CamelMultipart *multipart_body = NULL;
752 GSList *inline_attachments, *noninline_attachments;
753 gboolean build_alternative, build_related, build_calendar;
754 const gchar *str, *msg_class;
755 gboolean skip_set_content = FALSE;
756 gchar *ical_string = NULL;
757
758 g_return_val_if_fail (conn != NULL, NULL);
759 g_return_val_if_fail (object != NULL, NULL);
760
761 if (e_mapi_debug_is_enabled ()) {
762 printf ("%s:\n", G_STRFUNC);
763 e_mapi_debug_dump_object (object, TRUE, 3);
764 }
765
766 msg = camel_mime_message_new ();
767
768 str = e_mapi_util_find_array_propval (&object->properties, PidTagTransportMessageHeaders);
769 if (str && *str) {
770 CamelMimePart *part = camel_mime_part_new ();
771 CamelStream *stream;
772 CamelMimeParser *parser;
773
774 stream = camel_stream_mem_new_with_buffer (str, strlen (str));
775 parser = camel_mime_parser_new ();
776 camel_mime_parser_init_with_stream (parser, stream, NULL);
777 camel_mime_parser_scan_from (parser, FALSE);
778 g_object_unref (stream);
779
780 if (camel_mime_part_construct_from_parser_sync (part, parser, NULL, NULL)) {
781 const CamelNameValueArray *headers;
782 CamelMedium *msg_medium = CAMEL_MEDIUM (msg);
783 guint ii, len;
784
785 headers = camel_medium_get_headers (CAMEL_MEDIUM (part));
786 len = camel_name_value_array_get_length (headers);
787
788 for (ii = 0; ii < len; ii++) {
789 const gchar *header_name = NULL, *header_value = NULL;
790
791 /* skip all headers describing content of a message,
792 because it's overwritten on message decomposition */
793 if (!camel_name_value_array_get (headers, ii, &header_name, &header_value) ||
794 !header_name ||
795 g_ascii_strncasecmp (header_name, "Content", 7) == 0)
796 continue;
797
798 while (header_value && camel_mime_is_lwsp (*header_value))
799 header_value++;
800
801 camel_medium_add_header (msg_medium, header_name, header_value);
802 }
803 }
804
805 g_object_unref (parser);
806 g_object_unref (part);
807 } else {
808 CamelInternetAddress *to_addr, *cc_addr, *bcc_addr;
809 const struct FILETIME *msg_date;
810 const uint8_t *read_receipt;
811 const uint32_t *priority;
812 gchar *name, *email;
813
814 to_addr = camel_internet_address_new ();
815 cc_addr = camel_internet_address_new ();
816 bcc_addr = camel_internet_address_new ();
817
818 e_mapi_mail_utils_decode_recipients (conn, object->recipients, (CamelAddress *) to_addr, (CamelAddress *) cc_addr, (CamelAddress *) bcc_addr);
819
820 camel_mime_message_set_recipients (msg, CAMEL_RECIPIENT_TYPE_TO, to_addr);
821 camel_mime_message_set_recipients (msg, CAMEL_RECIPIENT_TYPE_CC, cc_addr);
822 camel_mime_message_set_recipients (msg, CAMEL_RECIPIENT_TYPE_BCC, bcc_addr);
823
824 g_object_unref (to_addr);
825 g_object_unref (cc_addr);
826 g_object_unref (bcc_addr);
827
828 msg_date = e_mapi_util_find_array_propval (&object->properties, PidTagClientSubmitTime);
829 if (!msg_date)
830 msg_date = e_mapi_util_find_array_propval (&object->properties, PidTagMessageDeliveryTime);
831 if (msg_date)
832 camel_mime_message_set_date (msg, e_mapi_util_filetime_to_time_t (msg_date), 0);
833
834 str = e_mapi_util_find_array_propval (&object->properties, PidTagSubject);
835 if (str)
836 camel_mime_message_set_subject (msg, str);
837
838 name = NULL;
839 email = NULL;
840
841 e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
842 PidTagSentRepresentingName,
843 PidTagSentRepresentingEmailAddress,
844 PidTagSentRepresentingAddressType,
845 &name, &email);
846
847 if (email && *email) {
848 CamelInternetAddress *addr;
849
850 addr = camel_internet_address_new ();
851 camel_internet_address_add (addr, name, email);
852 camel_mime_message_set_from (msg, addr);
853 g_object_unref (addr);
854 }
855
856 g_free (name);
857 g_free (email);
858
859 /* Threading */
860 str = e_mapi_util_find_array_propval (&object->properties, PidTagInternetMessageId);
861 if (str)
862 camel_medium_add_header (CAMEL_MEDIUM (msg), "Message-ID", str);
863
864 str = e_mapi_util_find_array_propval (&object->properties, PidTagInternetReferences);
865 if (str)
866 camel_medium_add_header (CAMEL_MEDIUM (msg), "References", str);
867
868 str = e_mapi_util_find_array_propval (&object->properties, PidTagInReplyToId);
869 if (str)
870 camel_medium_add_header (CAMEL_MEDIUM (msg), "In-Reply-To", str);
871
872 priority = e_mapi_util_find_array_propval (&object->properties, PidTagPriority);
873 if (priority && *priority == 1)
874 camel_medium_add_header (CAMEL_MEDIUM (msg), "X-Priority", "1");
875
876 /* Read-Receipt handling */
877 read_receipt = e_mapi_util_find_array_propval (&object->properties, PidTagReadReceiptRequested);
878 if (read_receipt && *read_receipt) {
879 if (!camel_medium_get_header (CAMEL_MEDIUM (msg), "Disposition-Notification-To")) {
880 name = NULL;
881 email = NULL;
882
883 e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
884 PidTagReadReceiptName,
885 PidTagReadReceiptEmailAddress,
886 PidTagReadReceiptAddressType,
887 &name, &email);
888
889 if (email && *email) {
890 CamelInternetAddress *addr;
891 gchar *address;
892
893 addr = camel_internet_address_new ();
894 camel_internet_address_add (addr, name, email);
895 address = camel_address_encode (CAMEL_ADDRESS (addr));
896
897 camel_medium_add_header (CAMEL_MEDIUM (msg), "Disposition-Notification-To", address);
898
899 g_object_unref (addr);
900 g_free (address);
901 }
902
903 g_free (name);
904 g_free (email);
905 }
906 }
907 }
908
909 str = e_mapi_util_find_array_propval (&object->properties, PidNameContentClass);
910 if (str)
911 camel_medium_add_header (CAMEL_MEDIUM (msg), "Content-class", str);
912
913 inline_attachments = NULL;
914 noninline_attachments = NULL;
915 msg_class = e_mapi_util_find_array_propval (&object->properties, PidTagMessageClass);
916 classify_attachments (conn, object->attachments, e_mapi_object_contains_prop (object, PidTagHtml), msg_class, &inline_attachments, &noninline_attachments);
917
918 build_calendar = msg_class && g_str_has_prefix (msg_class, IPM_SCHEDULE_MEETING_PREFIX);
919 if (build_calendar) {
920 ical_string = build_ical_string (conn, object, msg_class);
921 if (!ical_string)
922 build_calendar = FALSE;
923 }
924
925 build_alternative = !build_calendar
926 && e_mapi_object_contains_prop (object, PidTagHtml)
927 && e_mapi_object_contains_prop (object, PidTagBody);
928 build_related = !build_calendar && !build_alternative && inline_attachments
929 && e_mapi_object_contains_prop (object, PidTagHtml);
930
931 if (!build_alternative && !build_related && inline_attachments) {
932 noninline_attachments = g_slist_concat (noninline_attachments, inline_attachments);
933 inline_attachments = NULL;
934 }
935
936 if (build_calendar) {
937 g_return_val_if_fail (ical_string != NULL, msg);
938
939 camel_mime_part_set_content (CAMEL_MIME_PART (msg), ical_string, strlen (ical_string), "text/calendar");
940 } else if (build_alternative) {
941 multipart_body = build_multipart_alternative (object, inline_attachments);
942 } else if (build_related) {
943 multipart_body = build_multipart_related (object, inline_attachments);
944 } else if (noninline_attachments) {
945 /* Simple multipart/mixed */
946 CamelMimePart *part = camel_mime_part_new ();
947
948 multipart_body = camel_multipart_new ();
949 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (multipart_body), "multipart/mixed");
950 camel_multipart_set_boundary (multipart_body, NULL);
951 if (e_mapi_object_contains_prop (object, PidTagHtml))
952 build_body_part_content (part, object, PidTagHtml);
953 else
954 build_body_part_content (part, object, PidTagBody);
955 camel_multipart_add_part (multipart_body, part);
956 g_object_unref (part);
957 } else {
958 /* Flat message */
959 if (e_mapi_object_contains_prop (object, PidTagHtml))
960 build_body_part_content (CAMEL_MIME_PART (msg), object, PidTagHtml);
961 else
962 build_body_part_content (CAMEL_MIME_PART (msg), object, PidTagBody);
963 }
964
965 if (noninline_attachments) { /* multipart/mixed */
966 if (build_alternative || build_related || build_calendar) {
967 multipart_body = build_multipart_mixed (multipart_body, noninline_attachments);
968 } else if (g_slist_length (noninline_attachments) == 1 && msg_class && strstr (msg_class, ".SMIME") > msg_class) {
969 CamelMimePart *part = noninline_attachments->data;
970
971 skip_set_content = TRUE;
972
973 camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (part));
974
975 if (!strstr (msg_class, ".SMIME.")) {
976 /* encrypted */
977 camel_medium_set_content (CAMEL_MEDIUM (msg), camel_medium_get_content (CAMEL_MEDIUM (part)));
978 camel_mime_part_set_encoding (CAMEL_MIME_PART (msg), camel_mime_part_get_encoding (part));
979 } else {
980 /* signed */
981 camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (part));
982 }
983 } else {
984 add_multipart_attachments (multipart_body, noninline_attachments);
985 }
986 }
987
988 if (!skip_set_content && multipart_body)
989 camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (multipart_body));
990
991 if (multipart_body)
992 g_object_unref (multipart_body);
993 g_slist_free_full (inline_attachments, g_object_unref);
994 g_slist_free_full (noninline_attachments, g_object_unref);
995 g_free (ical_string);
996
997 return msg;
998 }
999
1000 static void
1001 e_mapi_mail_add_recipients (EMapiObject *object,
1002 CamelInternetAddress *addresses,
1003 OlMailRecipientType recip_type)
1004 {
1005 gint ii;
1006 const gchar *name = NULL, *email = NULL;
1007
1008 g_return_if_fail (object != NULL);
1009
1010 for (ii = 0; addresses && camel_internet_address_get (addresses, ii, &name, &email); ii++) {
1011 EMapiRecipient *recipient;
1012 uint32_t ui32 = 0;
1013 uint8_t bl;
1014
1015 recipient = e_mapi_recipient_new (object);
1016 e_mapi_object_add_recipient (object, recipient);
1017
1018 #define set_value(pt,vl) { \
1019 if (!e_mapi_utils_add_property (&recipient->properties, pt, vl, recipient)) { \
1020 g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt); \
1021 \
1022 return; \
1023 } \
1024 }
1025
1026 ui32 = recip_type;
1027 set_value (PidTagRecipientType, &ui32);
1028
1029 if (!name || !*name)
1030 name = email;
1031
1032 if (name && *name) {
1033 set_value (PidTagDisplayName, name);
1034 set_value (PidTagRecipientDisplayName, name);
1035 }
1036 if (email && *email) {
1037 set_value (PidTagAddressType, "SMTP");
1038 set_value (PidTagEmailAddress, email);
1039 set_value (PidTagSmtpAddress, email);
1040 }
1041
1042 ui32 = 0;
1043 set_value (PidTagSendInternetEncoding, &ui32);
1044
1045 ui32 = DT_MAILUSER;
1046 set_value (PidTagDisplayType, &ui32);
1047
1048 ui32 = MAPI_MAILUSER;
1049 set_value (PidTagObjectType, &ui32);
1050
1051 bl = 0;
1052 set_value (PidTagSendRichInfo, &bl);
1053
1054 #undef set_value
1055
1056 name = NULL;
1057 email = NULL;
1058 }
1059 }
1060
1061 static CamelStream *
1062 get_content_stream (CamelMimePart *part, GCancellable *cancellable)
1063 {
1064 CamelStream *content_stream;
1065 CamelStream *filter_stream = NULL;
1066 CamelMimeFilterWindows *windows = NULL;
1067 CamelDataWrapper *dw;
1068
1069 g_return_val_if_fail (part != NULL, NULL);
1070
1071 dw = camel_medium_get_content (CAMEL_MEDIUM (part));
1072 g_return_val_if_fail (dw != NULL, NULL);
1073
1074 content_stream = camel_stream_mem_new();
1075
1076 if (camel_mime_part_get_content_type (part)) {
1077 const gchar *charset = camel_content_type_param (camel_mime_part_get_content_type (part), "charset");
1078
1079 if (charset && *charset && g_ascii_strcasecmp (charset, "utf8") != 0 && g_ascii_strcasecmp (charset, "utf-8") != 0) {
1080 if (g_ascii_strncasecmp (charset, "iso-8859-", 9) == 0) {
1081 CamelStream *null;
1082
1083 /* Since a few Windows mailers like to claim they sent
1084 * out iso-8859-# encoded text when they really sent
1085 * out windows-cp125#, do some simple sanity checking
1086 * before we move on... */
1087
1088 null = camel_stream_null_new ();
1089 filter_stream = camel_stream_filter_new (null);
1090 g_object_unref (null);
1091
1092 windows = (CamelMimeFilterWindows *)camel_mime_filter_windows_new (charset);
1093 camel_stream_filter_add (
1094 CAMEL_STREAM_FILTER (filter_stream),
1095 CAMEL_MIME_FILTER (windows));
1096
1097 camel_data_wrapper_decode_to_stream_sync (
1098 dw, (CamelStream *)filter_stream, cancellable, NULL);
1099 camel_stream_flush ((CamelStream *)filter_stream, cancellable, NULL);
1100 g_object_unref (filter_stream);
1101
1102 charset = camel_mime_filter_windows_real_charset (windows);
1103 }
1104
1105 if (charset && *charset) {
1106 CamelMimeFilter *filter;
1107
1108 filter_stream = camel_stream_filter_new (content_stream);
1109
1110 if ((filter = camel_mime_filter_charset_new (charset, "UTF-8"))) {
1111 camel_stream_filter_add (
1112 CAMEL_STREAM_FILTER (filter_stream),
1113 CAMEL_MIME_FILTER (filter));
1114 g_object_unref (filter);
1115 } else {
1116 g_object_unref (filter_stream);
1117 filter_stream = NULL;
1118 }
1119 }
1120 }
1121 }
1122
1123 if (filter_stream) {
1124 camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) filter_stream, cancellable, NULL);
1125 camel_stream_flush (filter_stream, cancellable, NULL);
1126 g_object_unref (filter_stream);
1127 } else {
1128 camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
1129 }
1130
1131 if (windows)
1132 g_object_unref (windows);
1133
1134 g_seekable_seek (G_SEEKABLE (content_stream), 0, G_SEEK_SET, NULL, NULL);
1135
1136 return content_stream;
1137 }
1138
1139 static void
1140 e_mapi_mail_content_stream_to_bin (CamelStream *content_stream,
1141 uint64_t *pcb,
1142 uint8_t **plpb,
1143 TALLOC_CTX *mem_ctx,
1144 GCancellable *cancellable)
1145 {
1146 guint8 *buf;
1147 guint32 read_size;
1148 uint64_t cb;
1149 uint8_t *lpb;
1150
1151 g_return_if_fail (content_stream != NULL);
1152 g_return_if_fail (pcb != NULL);
1153 g_return_if_fail (plpb != NULL);
1154 g_return_if_fail (mem_ctx != NULL);
1155
1156 buf = g_new0 (guint8 , STREAM_SIZE);
1157
1158 cb = 0;
1159 lpb = NULL;
1160
1161 g_seekable_seek (G_SEEKABLE (content_stream), 0, G_SEEK_SET, NULL, NULL);
1162 while (read_size = camel_stream_read (content_stream, (gchar *) buf, STREAM_SIZE, cancellable, NULL), read_size > 0) {
1163 lpb = talloc_realloc (mem_ctx, lpb, uint8_t, cb + read_size);
1164 memcpy (lpb + cb, buf, read_size);
1165 cb += read_size;
1166 }
1167
1168 g_free (buf);
1169
1170 *pcb = cb;
1171 *plpb = lpb;
1172 }
1173
1174 static gboolean
1175 e_mapi_mail_part_is_attachment (CamelMimePart *part)
1176 {
1177 const CamelContentDisposition *content_disposition;
1178
1179 g_return_val_if_fail (CAMEL_IS_MIME_PART (part), FALSE);
1180
1181 content_disposition = camel_mime_part_get_content_disposition (part);
1182
1183 if (!content_disposition)
1184 return FALSE;
1185
1186 return content_disposition &&
1187 content_disposition->disposition && (
1188 g_ascii_strcasecmp (content_disposition->disposition, "attachment") == 0 ||
1189 g_ascii_strcasecmp (content_disposition->disposition, "inline") == 0);
1190 }
1191
1192 #define set_attach_value(pt,vl) { \
1193 if (!e_mapi_utils_add_property (&attach->properties, pt, vl, attach)) { \
1194 g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt); \
1195 return FALSE; \
1196 } \
1197 }
1198
1199 static gboolean
1200 e_mapi_mail_add_attach (EMapiObject *object,
1201 CamelMimePart *part,
1202 CamelStream *content_stream,
1203 GCancellable *cancellable)
1204 {
1205 EMapiAttachment *attach;
1206 CamelContentType *content_type;
1207 const gchar *content_id;
1208 const gchar *filename;
1209 uint64_t data_cb = 0;
1210 uint8_t *data_lpb = NULL;
1211 uint32_t ui32;
1212
1213 g_return_val_if_fail (object != NULL, FALSE);
1214 g_return_val_if_fail (part != NULL, FALSE);
1215 g_return_val_if_fail (content_stream != NULL, FALSE);
1216
1217 attach = e_mapi_attachment_new (object);
1218 e_mapi_object_add_attachment (object, attach);
1219
1220 ui32 = ATTACH_BY_VALUE;
1221 set_attach_value (PidTagAttachMethod, &ui32);
1222 ui32 = -1;
1223 set_attach_value (PidTagRenderingPosition, &ui32);
1224
1225 filename = camel_mime_part_get_filename (part);
1226 if (filename) {
1227 set_attach_value (PidTagAttachFilename, filename);
1228 set_attach_value (PidTagAttachLongFilename, filename);
1229 }
1230
1231 content_id = camel_mime_part_get_content_id (part);
1232 if (content_id)
1233 set_attach_value (PidTagAttachContentId, content_id);
1234
1235 content_type = camel_mime_part_get_content_type (part);
1236 if (content_type) {
1237 gchar *ct = camel_content_type_simple (content_type);
1238 if (ct)
1239 set_attach_value (PidTagAttachMimeTag, ct);
1240 g_free (ct);
1241 }
1242
1243 e_mapi_mail_content_stream_to_bin (content_stream, &data_cb, &data_lpb, attach, cancellable);
1244 e_mapi_attachment_add_streamed (attach, PidTagAttachDataBinary, data_cb, data_lpb);
1245
1246 return TRUE;
1247 }
1248
1249 static gboolean
1250 e_mapi_mail_add_body (EMapiObject *object,
1251 CamelStream *content_stream,
1252 uint32_t proptag,
1253 GCancellable *cancellable)
1254 {
1255 uint64_t data_cb = 0;
1256 uint8_t *data_lpb = NULL;
1257 gchar *str;
1258
1259 e_mapi_mail_content_stream_to_bin (content_stream, &data_cb, &data_lpb, object, cancellable);
1260 str = talloc_strndup (object, (const gchar *) data_lpb, data_cb);
1261 talloc_free (data_lpb);
1262
1263 if ((proptag & 0xFFFF) == PT_BINARY) {
1264 data_lpb = (uint8_t *) (str ? str : "");
1265 data_cb = strlen ((const gchar *) data_lpb) + 1;
1266 /* include trailing zero .................. ^^^ */
1267
1268 e_mapi_object_add_streamed (object, proptag, data_cb, data_lpb);
1269
1270 return TRUE;
1271 } else if (str) {
1272 if (!e_mapi_utils_add_property (&object->properties, proptag, str, object)) {
1273 talloc_free (str);
1274 return FALSE;
1275 }
1276
1277 talloc_free (str);
1278 } else {
1279 return e_mapi_utils_add_property (&object->properties, proptag, "", object);
1280 }
1281
1282 return TRUE;
1283 }
1284
1285 static gboolean
1286 e_mapi_mail_do_smime_encrypted (EMapiObject *object,
1287 CamelMedium *message,
1288 gchar **pmsg_class,
1289 gchar **ppid_name_content_type,
1290 GCancellable *cancellable)
1291 {
1292 EMapiAttachment *attach;
1293 CamelStream *content_stream;
1294 CamelDataWrapper *dw;
1295 CamelContentType *type;
1296 uint32_t ui32;
1297 uint64_t data_cb = 0;
1298 uint8_t *data_lpb = NULL;
1299 gchar *content_type_str;
1300
1301 g_return_val_if_fail (object != NULL, FALSE);
1302 g_return_val_if_fail (message != NULL, FALSE);
1303 g_return_val_if_fail (pmsg_class != NULL, FALSE);
1304 g_return_val_if_fail (ppid_name_content_type != NULL, FALSE);
1305
1306 g_free (*pmsg_class);
1307 *pmsg_class = g_strdup ("IPM.Note.SMIME");
1308
1309 type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message));
1310 dw = camel_medium_get_content (message);
1311 content_type_str = camel_content_type_format (type);
1312
1313 g_free (*ppid_name_content_type);
1314 *ppid_name_content_type = content_type_str; /* will be freed within the caller */
1315
1316 content_stream = camel_stream_mem_new ();
1317 camel_data_wrapper_decode_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
1318
1319 attach = e_mapi_attachment_new (object);
1320 e_mapi_object_add_attachment (object, attach);
1321
1322 ui32 = ATTACH_BY_VALUE;
1323 set_attach_value (PidTagAttachMethod, &ui32);
1324 ui32 = -1;
1325 set_attach_value (PidTagRenderingPosition, &ui32);
1326 set_attach_value (PidTagAttachMimeTag, content_type_str);
1327 set_attach_value (PidTagAttachFilename, "SMIME.txt");
1328 set_attach_value (PidTagAttachLongFilename, "SMIME.txt");
1329 set_attach_value (PidTagDisplayName, "SMIME.txt");
1330
1331 e_mapi_mail_content_stream_to_bin (content_stream, &data_cb, &data_lpb, attach, cancellable);
1332 e_mapi_attachment_add_streamed (attach, PidTagAttachDataBinary, data_cb, data_lpb);
1333
1334 g_object_unref (content_stream);
1335
1336 return TRUE;
1337 }
1338
1339 static gboolean
1340 e_mapi_mail_do_smime_signed (EMapiObject *object,
1341 CamelMultipart *multipart,
1342 gchar **pmsg_class,
1343 GCancellable *cancellable)
1344 {
1345 EMapiAttachment *attach;
1346 CamelMimePart *content, *signature;
1347 CamelStream *content_stream;
1348 CamelContentType *type;
1349 CamelDataWrapper *dw;
1350 uint32_t ui32;
1351 uint64_t data_cb = 0;
1352 uint8_t *data_lpb = NULL;
1353 gchar *content_type_str, *content_type_unfolded;
1354
1355 g_free (*pmsg_class);
1356 *pmsg_class = g_strdup ("IPM.Note.SMIME.MultipartSigned");
1357
1358 content = camel_multipart_get_part (multipart, CAMEL_MULTIPART_SIGNED_CONTENT);
1359 signature = camel_multipart_get_part (multipart, CAMEL_MULTIPART_SIGNED_SIGNATURE);
1360
1361 g_return_val_if_fail (content != NULL, FALSE);
1362 g_return_val_if_fail (signature != NULL, FALSE);
1363
1364 content_stream = get_content_stream (content, cancellable);
1365 type = camel_mime_part_get_content_type (content);
1366
1367 if (camel_content_type_is (type, "text", "plain")) {
1368 e_mapi_mail_add_body (object, content_stream, PidTagBody, cancellable);
1369 } else if (camel_content_type_is (type, "text", "html")) {
1370 e_mapi_mail_add_body (object, content_stream, PidTagHtml, cancellable);
1371 } else {
1372 e_mapi_mail_add_attach (object, content, content_stream, cancellable);
1373 }
1374
1375 if (content_stream)
1376 g_object_unref (content_stream);
1377
1378 content_stream = camel_stream_mem_new ();
1379 dw = CAMEL_DATA_WRAPPER (multipart);
1380 type = camel_data_wrapper_get_mime_type_field (dw);
1381 content_type_str = camel_content_type_format (type);
1382 content_type_unfolded = camel_header_unfold (content_type_str);
1383
1384 #define wstr(str) camel_stream_write (content_stream, str, strlen (str), cancellable, NULL)
1385 wstr("Content-Type: ");
1386 wstr(content_type_unfolded);
1387 wstr("\r\n\r\n");
1388 #undef wstr
1389
1390 g_free (content_type_str);
1391 g_free (content_type_unfolded);
1392
1393 camel_data_wrapper_write_to_stream_sync (dw, (CamelStream *) content_stream, cancellable, NULL);
1394
1395 attach = e_mapi_attachment_new (object);
1396 e_mapi_object_add_attachment (object, attach);
1397
1398 ui32 = ATTACH_BY_VALUE;
1399 set_attach_value (PidTagAttachMethod, &ui32);
1400 ui32 = -1;
1401 set_attach_value (PidTagRenderingPosition, &ui32);
1402 set_attach_value (PidTagAttachMimeTag, "multipart/signed");
1403 set_attach_value (PidTagAttachFilename, "SMIME.txt");
1404 set_attach_value (PidTagAttachLongFilename, "SMIME.txt");
1405 set_attach_value (PidTagDisplayName, "SMIME.txt");
1406
1407 e_mapi_mail_content_stream_to_bin (content_stream, &data_cb, &data_lpb, attach, cancellable);
1408 e_mapi_attachment_add_streamed (attach, PidTagAttachDataBinary, data_cb, data_lpb);
1409
1410 g_object_unref (content_stream);
1411
1412 return TRUE;
1413 }
1414
1415 static gboolean
1416 e_mapi_mail_do_multipart (EMapiObject *object,
1417 CamelMultipart *mp,
1418 gboolean *is_first,
1419 GCancellable *cancellable)
1420 {
1421 CamelDataWrapper *dw;
1422 CamelStream *content_stream;
1423 CamelContentType *type;
1424 CamelMimePart *part;
1425 gboolean parent_is_alternative;
1426 gint nn, ii;
1427
1428 g_return_val_if_fail (is_first != NULL, FALSE);
1429
1430 type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (mp));
1431 parent_is_alternative = type && camel_content_type_is (type, "multipart", "alternative");
1432
1433 nn = camel_multipart_get_number (mp);
1434 for (ii = 0; ii < nn; ii++) {
1435 /* getting part */
1436 part = camel_multipart_get_part (mp, ii);
1437 if (!part)
1438 continue;
1439
1440 dw = camel_medium_get_content (CAMEL_MEDIUM (part));
1441 if (CAMEL_IS_MULTIPART (dw)) {
1442 /* recursive */
1443 if (!e_mapi_mail_do_multipart (object, CAMEL_MULTIPART (dw), is_first, cancellable))
1444 return FALSE;
1445 continue;
1446 }
1447
1448 if (CAMEL_IS_MIME_MESSAGE (dw)) {
1449 CamelMimeMessage *message;
1450 EMapiObject *embedded = NULL;
1451 EMapiAttachment *attach;
1452
1453 attach = e_mapi_attachment_new (object);
1454 message = CAMEL_MIME_MESSAGE (dw);
1455 if (e_mapi_mail_utils_message_to_object (message, 0, E_MAPI_CREATE_FLAG_NONE, &embedded, attach, cancellable, NULL)) {
1456 uint32_t ui32;
1457 const gchar *str;
1458
1459 e_mapi_object_add_attachment (object, attach);
1460 attach->embedded_object = embedded;
1461 embedded->parent = object;
1462
1463 ui32 = ATTACH_EMBEDDED_MSG;
1464 set_attach_value (PidTagAttachMethod, &ui32);
1465 ui32 = 0;
1466 set_attach_value (PidTagRenderingPosition, &ui32);
1467 set_attach_value (PidTagAttachMimeTag, "message/rfc822");
1468
1469 str = camel_mime_message_get_subject (message);
1470 if (str)
1471 set_attach_value (PidTagAttachFilename, str);
1472 continue;
1473 } else {
1474 e_mapi_attachment_free (attach);
1475 }
1476 }
1477
1478 content_stream = get_content_stream (part, cancellable);
1479 type = camel_mime_part_get_content_type (part);
1480
1481 if (ii == 0 && (*is_first) && camel_content_type_is (type, "text", "plain")) {
1482 e_mapi_mail_add_body (object, content_stream, PidTagBody, cancellable);
1483 *is_first = FALSE;
1484 } else if ((ii == 0 || parent_is_alternative) &&
1485 camel_content_type_is (type, "text", "html") &&
1486 !e_mapi_mail_part_is_attachment (part)) {
1487 e_mapi_mail_add_body (object, content_stream, PidTagHtml, cancellable);
1488 } else {
1489 e_mapi_mail_add_attach (object, part, content_stream, cancellable);
1490 }
1491
1492 if (content_stream)
1493 g_object_unref (content_stream);
1494 }
1495
1496 return TRUE;
1497 }
1498
1499 #undef set_attach_value
1500
1501 gboolean
1502 e_mapi_mail_utils_message_to_object (struct _CamelMimeMessage *message,
1503 guint32 message_camel_flags,
1504 EMapiCreateFlags create_flags,
1505 EMapiObject **pobject,
1506 TALLOC_CTX *mem_ctx,
1507 GCancellable *cancellable,
1508 GError **perror)
1509 {
1510 EMapiObject *object;
1511 CamelContentType *content_type;
1512 CamelInternetAddress *addresses;
1513 const gchar *namep = NULL, *addressp = NULL;
1514 const gchar *str;
1515 gchar *msg_class = NULL;
1516 gchar *pid_name_content_type = NULL;
1517 gint ii = 0;
1518 uint32_t ui32;
1519 uint8_t bl;
1520
1521 g_return_val_if_fail (message != NULL, FALSE);
1522 g_return_val_if_fail (pobject != NULL, FALSE);
1523 g_return_val_if_fail (*pobject == NULL, FALSE);
1524 g_return_val_if_fail (mem_ctx != NULL, FALSE);
1525
1526 content_type = camel_data_wrapper_get_mime_type_field (CAMEL_DATA_WRAPPER (message));
1527 g_return_val_if_fail (content_type != NULL, FALSE);
1528
1529 /* headers */
1530 if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) == 0) {
1531 /* though invalid, then possible, to pass in a message without any 'from' */
1532 CamelInternetAddress *from = camel_mime_message_get_from (message);
1533 if (!from || !camel_internet_address_get (from, 0, &namep, &addressp))
1534 namep = NULL;
1535 }
1536
1537 object = e_mapi_object_new (mem_ctx);
1538
1539 #define set_value(pt,vl) { \
1540 if (!e_mapi_utils_add_property (&object->properties, pt, vl, object)) { \
1541 e_mapi_object_free (object); \
1542 g_free (msg_class); \
1543 g_free (pid_name_content_type); \
1544 \
1545 g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt); \
1546 \
1547 return FALSE; \
1548 } \
1549 }
1550
1551 ui32 = 65001; /* UTF8 - also used with PR_HTML */
1552 set_value (PidTagInternetCodepage, &ui32);
1553
1554 if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) == 0) {
1555 if ((message_camel_flags & CAMEL_MESSAGE_ANSWERED) != 0 ||
1556 (message_camel_flags & CAMEL_MESSAGE_ANSWERED_ALL) != 0) {
1557 ui32 = 0x105;
1558 set_value (PidTagIconIndex, &ui32);
1559 } else if ((message_camel_flags & CAMEL_MESSAGE_FORWARDED) != 0) {
1560 ui32 = 0x106;
1561 set_value (PidTagIconIndex, &ui32);
1562 }
1563
1564 ui32 = 0;
1565 if (message_camel_flags & CAMEL_MESSAGE_SEEN)
1566 ui32 |= MSGFLAG_READ;
1567 if (message_camel_flags & CAMEL_MESSAGE_ATTACHMENTS)
1568 ui32 |= MSGFLAG_HASATTACH;
1569 } else {
1570 ui32 = MSGFLAG_UNSENT;
1571 }
1572 set_value (PidTagMessageFlags, &ui32);
1573
1574 bl = 0;
1575 set_value (PidTagSendRichInfo, &bl);
1576
1577 /* PidTagConversationTopic and PidTagNormalizedSubject, together with PidTagSubjectPrefix
1578 are computed from PidTagSubject by a server */
1579 str = camel_mime_message_get_subject (message);
1580 if (str)
1581 set_value (PidTagSubject, str);
1582
1583 /* some properties may not be set when submitting a message */
1584 if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) == 0) {
1585 time_t msg_time = 0;
1586 gint msg_time_offset = 0;
1587 CamelNameValueArray *headers;
1588
1589 if (namep && *namep)
1590 set_value (PidTagSentRepresentingName, namep);
1591
1592 if (addressp && *addressp) {
1593 set_value (PidTagSentRepresentingAddressType, "SMTP");
1594 set_value (PidTagSentRepresentingEmailAddress, addressp);
1595 }
1596
1597 msg_time = camel_mime_message_get_date (message, &msg_time_offset);
1598 if (msg_time == CAMEL_MESSAGE_DATE_CURRENT)
1599 msg_time = camel_mime_message_get_date_received (message, &msg_time_offset);
1600 if (msg_time != 0) {
1601 struct FILETIME msg_date = { 0 };
1602
1603 e_mapi_util_time_t_to_filetime (msg_time, &msg_date);
1604
1605 set_value (PidTagClientSubmitTime, &msg_date);
1606 }
1607
1608 msg_time = camel_mime_message_get_date_received (message, &msg_time_offset);
1609 if (msg_time != 0) {
1610 struct FILETIME msg_date = { 0 };
1611
1612 e_mapi_util_time_t_to_filetime (msg_time, &msg_date);
1613
1614 set_value (PidTagMessageDeliveryTime, &msg_date);
1615 }
1616
1617 headers = camel_medium_dup_headers (CAMEL_MEDIUM (message));
1618 if (headers) {
1619 GString *hstr = g_string_new ("");
1620 guint len;
1621
1622 len = camel_name_value_array_get_length (headers);
1623
1624 for (ii = 0; ii < len; ii++) {
1625 const gchar *header_name = NULL, *header_value = NULL;
1626
1627 if (!camel_name_value_array_get (headers, ii, &header_name, &header_value) ||
1628 !header_name || !*header_name || g_ascii_strncasecmp (header_name, "X-Evolution", 11) == 0)
1629 continue;
1630
1631 g_string_append_printf (hstr, "%s: %s\n", header_name, header_value ? header_value : "");
1632 }
1633
1634 camel_name_value_array_free (headers);
1635
1636 if (hstr->len && hstr->str)
1637 set_value (PidTagTransportMessageHeaders, hstr->str);
1638
1639 g_string_free (hstr, TRUE);
1640 }
1641 }
1642
1643 str = camel_medium_get_header ((CamelMedium *) message, "References");
1644 if (str)
1645 set_value (PidTagInternetReferences, str);
1646
1647 str = camel_medium_get_header ((CamelMedium *) message, "In-Reply-To");
1648 if (str)
1649 set_value (PidTagInReplyToId, str);
1650
1651 str = camel_medium_get_header ((CamelMedium *) message, "Message-ID");
1652 if (str)
1653 set_value (PidTagInternetMessageId, str);
1654
1655 str = camel_medium_get_header ((CamelMedium *) message, "X-Priority");
1656 if (str && g_str_equal (str, "1")) {
1657 ui32 = 1;
1658 set_value (PidTagPriority, &ui32);
1659 }
1660
1661 str = camel_medium_get_header ((CamelMedium *) message, "Disposition-Notification-To");
1662 if (str) {
1663 CamelInternetAddress *addr;
1664
1665 namep = NULL;
1666 addressp = NULL;
1667
1668 addr = camel_internet_address_new ();
1669 if (camel_address_decode (CAMEL_ADDRESS (addr), str) != -1 &&
1670 camel_internet_address_get (addr, 0, &namep, &addressp) &&
1671 addressp && *addressp) {
1672 if (namep && *namep)
1673 set_value (PidTagReadReceiptName, namep);
1674
1675 set_value (PidTagReadReceiptEmailAddress, addressp);
1676 set_value (PidTagReadReceiptAddressType, "SMTP");
1677
1678 if ((create_flags & E_MAPI_CREATE_FLAG_SUBMIT) != 0) {
1679 bl = 1;
1680
1681 set_value (PidTagReadReceiptRequested, &bl);
1682 }
1683 }
1684
1685 g_object_unref (addr);
1686 }
1687
1688 addresses = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_TO);
1689 e_mapi_mail_add_recipients (object, addresses, olTo);
1690
1691 addresses = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_CC);
1692 e_mapi_mail_add_recipients (object, addresses, olCC);
1693
1694 addresses = camel_mime_message_get_recipients (message, CAMEL_RECIPIENT_TYPE_BCC);
1695 e_mapi_mail_add_recipients (object, addresses, olBCC);
1696
1697 if (camel_content_type_is (content_type, "application", "x-pkcs7-mime") ||
1698 camel_content_type_is (content_type, "application", "pkcs7-mime")) {
1699 e_mapi_mail_do_smime_encrypted (object, CAMEL_MEDIUM (message), &msg_class, &pid_name_content_type, cancellable);
1700 } else {
1701 CamelDataWrapper *dw = NULL;
1702 CamelStream *content_stream;
1703 CamelMultipart *multipart;
1704
1705 /* contents body */
1706 dw = camel_medium_get_content (CAMEL_MEDIUM (message));
1707 if (CAMEL_IS_MULTIPART (dw)) {
1708 gboolean is_first = TRUE;
1709
1710 multipart = CAMEL_MULTIPART (dw);
1711
1712 if (CAMEL_IS_MULTIPART_SIGNED (multipart) && camel_multipart_get_number (multipart) == 2) {
1713 e_mapi_mail_do_smime_signed (object, multipart, &msg_class, cancellable);
1714 } else {
1715 e_mapi_mail_do_multipart (object, multipart, &is_first, cancellable);
1716 }
1717 } else if (dw) {
1718 CamelContentType *type;
1719 CamelMimePart *part = CAMEL_MIME_PART (message);
1720
1721 content_stream = get_content_stream (part, cancellable);
1722 type = camel_data_wrapper_get_mime_type_field (dw);
1723
1724 if (camel_content_type_is (type, "text", "plain")) {
1725 e_mapi_mail_add_body (object, content_stream, PidTagBody, cancellable);
1726 } else if (camel_content_type_is (type, "text", "html")) {
1727 e_mapi_mail_add_body (object, content_stream, PidTagHtml, cancellable);
1728 } else {
1729 e_mapi_mail_add_attach (object, part, content_stream, cancellable);
1730 }
1731
1732 if (content_stream)
1733 g_object_unref (content_stream);
1734 }
1735 }
1736
1737 if (msg_class)
1738 set_value (PidTagMessageClass, msg_class);
1739
1740 if (pid_name_content_type)
1741 set_value (PidNameContentType, pid_name_content_type);
1742
1743 g_free (msg_class);
1744 g_free (pid_name_content_type);
1745
1746 *pobject = object;
1747
1748 #undef set_value
1749
1750 if (e_mapi_debug_is_enabled ()) {
1751 printf ("%s:\n", G_STRFUNC);
1752 e_mapi_debug_dump_object (object, TRUE, 3);
1753 }
1754
1755 return TRUE;
1756 }