static void dump_mime_struct (CamelMimePart *mime_part, gint depth) { CamelDataWrapper *content; gchar *mime_type; gint i = 0; while (i < depth) { printf (" "); i++; } content = camel_medium_get_content ((CamelMedium *) mime_part); mime_type = camel_data_wrapper_get_mime_type (content); printf ("Content-Type: %s\n", mime_type); g_free (mime_type); if (CAMEL_IS_MULTIPART (content)) { guint num, index = 0; num = camel_multipart_get_number ((CamelMultipart *) content); while (index < num) { mime_part = camel_multipart_get_part ((CamelMultipart *) content, index); dump_mime_struct (mime_part, depth + 1); index++; } } else if (CAMEL_IS_MIME_MESSAGE (content)) { dump_mime_struct ((CamelMimePart *) content, depth + 1); } }
gint test_message_compare (CamelMimeMessage *msg) { CamelMimeMessage *msg2; CamelStream *stream1; CamelStream *stream2; GByteArray *byte_array1; GByteArray *byte_array2; byte_array1 = g_byte_array_new (); stream1 = camel_stream_mem_new_with_byte_array (byte_array1); check_msg (camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (msg), stream1, NULL, NULL) != -1, "write_to_stream 1 failed", NULL); g_seekable_seek (G_SEEKABLE (stream1), 0, G_SEEK_SET, NULL, NULL); msg2 = camel_mime_message_new (); check_msg (camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (msg2), stream1, NULL, NULL) != -1, "construct_from_stream 1 failed"); g_seekable_seek (G_SEEKABLE (stream1), 0, G_SEEK_SET, NULL, NULL); byte_array2 = g_byte_array_new (); stream2 = camel_stream_mem_new_with_byte_array (byte_array2); check_msg (camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (msg2), stream2, NULL, NULL) != -1, "write_to_stream 2 failed"); g_seekable_seek (G_SEEKABLE (stream2), 0, G_SEEK_SET, NULL, NULL); if (byte_array1->len != byte_array2->len) { CamelDataWrapper *content; printf ("stream1 stream:\n%.*s\n", byte_array1->len, byte_array1->data); printf ("stream2 stream:\n%.*s\n\n", byte_array2->len, byte_array2->data); printf ("msg1:\n"); test_message_dump_structure (msg); printf ("msg2:\n"); test_message_dump_structure (msg2); content = camel_medium_get_content ((CamelMedium *) msg); } check_unref (msg2, 1); check_msg ( byte_array1->len == byte_array2->len, "byte_array1->len = %d, byte_array2->len = %d", byte_array1->len, byte_array2->len); check_msg (memcmp (byte_array1->data, byte_array2->data, byte_array1->len) == 0, "msg/stream compare"); g_object_unref (stream1); g_object_unref (stream2); return 0; }
static gboolean emfe_error_format (EMailFormatterExtension *extension, EMailFormatter *formatter, EMailFormatterContext *context, EMailPart *part, GOutputStream *stream, GCancellable *cancellable) { GOutputStream *filtered_stream; CamelMimeFilter *filter; CamelMimePart *mime_part; CamelDataWrapper *dw; const gchar *string; gchar *html; mime_part = e_mail_part_ref_mime_part (part); dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); html = g_strdup_printf ( "<div class=\"part-container -e-mail-formatter-frame-color " "-e-mail-formatter-body-color -e-web-view-text-color\">" "<div class=\"part-container-inner-margin pre\">\n" "<table border=\"0\" cellspacing=\"10\" " "cellpadding=\"0\" width=\"100%%\">\n" "<tr valign=\"top\"><td width=50>" "<img src=\"gtk-stock://%s/?size=%d\" /></td>\n" "<td style=\"color: red;\">", "dialog-error", GTK_ICON_SIZE_DIALOG); g_output_stream_write_all ( stream, html, strlen (html), NULL, cancellable, NULL); g_free (html); filter = camel_mime_filter_tohtml_new ( CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); filtered_stream = camel_filter_output_stream_new (stream, filter); g_object_unref (filter); camel_data_wrapper_decode_to_output_stream_sync ( dw, filtered_stream, cancellable, NULL); g_output_stream_flush (filtered_stream, cancellable, NULL); g_object_unref (filtered_stream); string = "</td></tr></table></div></div>"; g_output_stream_write_all ( stream, string, strlen (string), NULL, cancellable, NULL); g_object_unref (mime_part); return TRUE; }
static void message_dump_rec (CamelMimeMessage *msg, CamelMimePart *part, gint depth) { CamelDataWrapper *containee; gint parts, i; gchar *s; gchar *mime_type; s = alloca (depth + 1); memset (s, ' ', depth); s[depth] = 0; mime_type = camel_data_wrapper_get_mime_type ((CamelDataWrapper *) part); printf ("%sPart <%s>\n", s, G_OBJECT_TYPE_NAME (part)); printf ("%sContent-Type: %s\n", s, mime_type); g_free (mime_type); printf ("%s encoding: %s\n", s, camel_transfer_encoding_to_string (((CamelDataWrapper *)part)->encoding)); printf ("%s part encoding: %s\n", s, camel_transfer_encoding_to_string (camel_mime_part_get_encoding (part))); containee = camel_medium_get_content (CAMEL_MEDIUM (part)); if (containee == NULL) return; mime_type = camel_data_wrapper_get_mime_type (containee); printf ("%sContent <%s>\n", s, G_OBJECT_TYPE_NAME (containee)); printf ("%sContent-Type: %s\n", s, mime_type); g_free (mime_type); printf ("%s encoding: %s\n", s, camel_transfer_encoding_to_string (((CamelDataWrapper *)containee)->encoding)); /* using the object types is more accurate than using the mime/types */ if (CAMEL_IS_MULTIPART (containee)) { parts = camel_multipart_get_number (CAMEL_MULTIPART (containee)); for (i = 0; i < parts; i++) { CamelMimePart *part = camel_multipart_get_part (CAMEL_MULTIPART (containee), i); message_dump_rec (msg, part, depth + 1); } } else if (CAMEL_IS_MIME_MESSAGE (containee)) { message_dump_rec (msg, (CamelMimePart *) containee, depth + 1); } }
static void mail_attachment_handler_update_actions (EAttachmentView *view, EAttachmentHandler *handler) { EAttachment *attachment; CamelMimePart *mime_part; GtkActionGroup *action_group; GList *selected; gboolean visible = FALSE; selected = e_attachment_view_get_selected_attachments (view); if (g_list_length (selected) != 1) goto exit; attachment = E_ATTACHMENT (selected->data); if (e_attachment_get_loading (attachment) || e_attachment_get_saving (attachment)) goto exit; mime_part = e_attachment_ref_mime_part (attachment); if (mime_part != NULL) { CamelMedium *medium; CamelDataWrapper *content; medium = CAMEL_MEDIUM (mime_part); content = camel_medium_get_content (medium); visible = CAMEL_IS_MIME_MESSAGE (content); g_object_unref (mime_part); } exit: action_group = e_attachment_view_get_action_group (view, "mail"); gtk_action_group_set_visible (action_group, visible); g_list_foreach (selected, (GFunc) g_object_unref, NULL); g_list_free (selected); }
/* there is also an identical copy of this in camel-filter-search.c */ gboolean camel_search_message_body_contains (CamelDataWrapper *object, regex_t *pattern) { CamelDataWrapper *containee; gint truth = FALSE; gint parts, i; containee = camel_medium_get_content (CAMEL_MEDIUM (object)); if (containee == NULL) return FALSE; /* using the object types is more accurate than using the mime/types */ if (CAMEL_IS_MULTIPART (containee)) { parts = camel_multipart_get_number (CAMEL_MULTIPART (containee)); for (i = 0; i < parts && truth == FALSE; i++) { CamelDataWrapper *part = (CamelDataWrapper *)camel_multipart_get_part (CAMEL_MULTIPART (containee), i); if (part) truth = camel_search_message_body_contains (part, pattern); } } else if (CAMEL_IS_MIME_MESSAGE (containee)) { /* for messages we only look at its contents */ truth = camel_search_message_body_contains ((CamelDataWrapper *)containee, pattern); } else if (camel_content_type_is(CAMEL_DATA_WRAPPER (containee)->mime_type, "text", "*") || camel_content_type_is(CAMEL_DATA_WRAPPER (containee)->mime_type, "x-evolution", "evolution-rss-feed")) { /* for all other text parts, we look inside, otherwise we dont care */ CamelStream *stream; GByteArray *byte_array; byte_array = g_byte_array_new (); stream = camel_stream_mem_new_with_byte_array (byte_array); camel_data_wrapper_write_to_stream_sync ( containee, stream, NULL, NULL); camel_stream_write (stream, "", 1, NULL, NULL); truth = regexec (pattern, (gchar *) byte_array->data, 0, NULL, 0) == 0; g_object_unref (stream); } return truth; }
static void set_attachments (ECalClient *client, ECalComponent *comp, CamelMimeMessage *message) { /* XXX Much of this is copied from CompEditor::get_attachment_list(). * Perhaps it should be split off as a separate utility? */ EAttachmentStore *store; CamelDataWrapper *content; CamelMultipart *multipart; GFile *destination; GList *attachment_list = NULL; GSList *uri_list = NULL; const gchar *comp_uid = NULL; const gchar *local_store; gchar *filename_prefix, *tmp; gint ii, n_parts; struct _att_async_cb_data cb_data; cb_data.flag = e_flag_new (); cb_data.uris = NULL; content = camel_medium_get_content ((CamelMedium *) message); if (!content || !CAMEL_IS_MULTIPART (content)) return; n_parts = camel_multipart_get_number (CAMEL_MULTIPART (content)); if (n_parts < 1) return; e_cal_component_get_uid (comp, &comp_uid); g_return_if_fail (comp_uid != NULL); tmp = g_strdup (comp_uid); e_filename_make_safe (tmp); filename_prefix = g_strconcat (tmp, "-", NULL); g_free (tmp); local_store = e_cal_client_get_local_attachment_store (client); destination = g_file_new_for_path (local_store); /* Create EAttachments from the MIME parts and add them to the * attachment store. */ multipart = CAMEL_MULTIPART (content); store = E_ATTACHMENT_STORE (e_attachment_store_new ()); for (ii = 1; ii < n_parts; ii++) { EAttachment *attachment; CamelMimePart *mime_part; attachment = e_attachment_new (); mime_part = camel_multipart_get_part (multipart, ii); e_attachment_set_mime_part (attachment, mime_part); attachment_list = g_list_append (attachment_list, attachment); } e_flag_clear (cb_data.flag); e_attachment_store_load_async ( store, attachment_list, (GAsyncReadyCallback) attachment_load_finished, &cb_data); /* Loading should be instantaneous since we already have * the full content, but we need to wait for the callback. */ e_flag_wait (cb_data.flag); g_list_foreach (attachment_list, (GFunc) g_object_unref, NULL); g_list_free (attachment_list); cb_data.uris = NULL; e_flag_clear (cb_data.flag); e_attachment_store_save_async ( store, destination, filename_prefix, (GAsyncReadyCallback) attachment_save_finished, &cb_data); g_free (filename_prefix); /* We can't return until we have results. */ e_flag_wait (cb_data.flag); if (cb_data.uris == NULL) { e_flag_free (cb_data.flag); g_warning ("No attachment URIs retrieved."); return; } /* Transfer the URI strings to the GSList. */ for (ii = 0; cb_data.uris[ii] != NULL; ii++) { uri_list = g_slist_prepend (uri_list, cb_data.uris[ii]); cb_data.uris[ii] = NULL; } e_flag_free (cb_data.flag); g_free (cb_data.uris); /* XXX Does this take ownership of the list? */ e_cal_component_set_attachment_list (comp, uri_list); e_attachment_store_remove_all (store); g_object_unref (destination); g_object_unref (store); }
static void set_description (ECalComponent *comp, CamelMimeMessage *message) { CamelDataWrapper *content; CamelStream *stream; CamelContentType *type; CamelMimePart *mime_part = CAMEL_MIME_PART (message); ECalComponentText *text = NULL; GByteArray *byte_array; GSList *sl = NULL; gchar *str, *convert_str = NULL; gsize bytes_read, bytes_written; gint count = 2; content = camel_medium_get_content ((CamelMedium *) message); if (!content) return; /* * Get non-multipart content from multipart message. */ while (CAMEL_IS_MULTIPART (content) && count > 0) { mime_part = camel_multipart_get_part (CAMEL_MULTIPART (content), 0); content = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); count--; } if (!mime_part) return; type = camel_mime_part_get_content_type (mime_part); if (!camel_content_type_is (type, "text", "plain")) return; byte_array = g_byte_array_new (); stream = camel_stream_mem_new_with_byte_array (byte_array); camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL); str = g_strndup ((gchar *) byte_array->data, byte_array->len); g_object_unref (stream); /* convert to UTF-8 string */ if (str && content->mime_type->params && content->mime_type->params->value) { convert_str = g_convert ( str, strlen (str), "UTF-8", content->mime_type->params->value, &bytes_read, &bytes_written, NULL); } text = g_new0 (ECalComponentText, 1); if (convert_str) text->value = prepend_from (message, &convert_str); else text->value = prepend_from (message, &str); text->altrep = NULL; sl = g_slist_append (sl, text); e_cal_component_set_description_list (comp, sl); g_free (str); if (convert_str) g_free (convert_str); e_cal_component_free_text_list (sl); }
static gboolean empe_mp_alternative_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelMultipart *mp; gint i, nparts, bestid = 0; CamelMimePart *best = NULL; EMailExtensionRegistry *reg; reg = e_mail_parser_get_extension_registry (parser); mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); if (!CAMEL_IS_MULTIPART (mp)) return e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); /* as per rfc, find the last part we know how to display */ nparts = camel_multipart_get_number (mp); for (i = 0; i < nparts; i++) { CamelMimePart *mpart; CamelDataWrapper *data_wrapper; CamelContentType *type; gchar *mime_type; gsize content_size; if (g_cancellable_is_cancelled (cancellable)) return TRUE; /* is it correct to use the passed in *part here? */ mpart = camel_multipart_get_part (mp, i); if (mpart == NULL) continue; /* This may block even though the stream does not. * XXX Pretty inefficient way to test if the MIME part * is empty. Surely there's a quicker way? */ data_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mpart)); content_size = camel_data_wrapper_calculate_decoded_size_sync (data_wrapper, cancellable, NULL); if (content_size == 0) continue; type = camel_mime_part_get_content_type (mpart); mime_type = camel_content_type_simple (type); camel_strdown (mime_type); if (!e_mail_part_is_attachment (mpart) && ((camel_content_type_is (type, "multipart", "related") == 0) || !related_display_part_is_attachment (mpart)) && (e_mail_extension_registry_get_for_mime_type (reg, mime_type) || ((best == NULL) && (e_mail_extension_registry_get_fallback (reg, mime_type))))) { best = mpart; bestid = i; } g_free (mime_type); } if (best) { gint len = part_id->len; g_string_append_printf (part_id, ".alternative.%d", bestid); e_mail_parser_parse_part ( parser, best, part_id, cancellable, out_mail_parts); g_string_truncate (part_id, len); } else { e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); } return TRUE; }
static gboolean empe_inlinepgp_signed_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelStream *filtered_stream; CamelMimeFilterPgp *pgp_filter; CamelContentType *content_type; CamelCipherContext *cipher; CamelCipherValidity *valid; CamelDataWrapper *dw; CamelMimePart *opart; CamelStream *ostream; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; gchar *type; gint len; GError *local_error = NULL; GByteArray *ba; if (g_cancellable_is_cancelled (cancellable) || /* avoid recursion */ (part_id->str && part_id->len > 17 && g_str_has_suffix (part_id->str, ".inlinepgp_signed"))) return FALSE; cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); /* Verify the signature of the message */ valid = camel_cipher_context_verify_sync ( cipher, part, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Error verifying signature: %s"), local_error->message); g_error_free (local_error); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); g_object_unref (cipher); return TRUE; } /* Setup output stream */ ostream = camel_stream_mem_new (); filtered_stream = camel_stream_filter_new (ostream); /* Add PGP header / footer filter */ pgp_filter = (CamelMimeFilterPgp *) camel_mime_filter_pgp_new (); camel_stream_filter_add ( CAMEL_STREAM_FILTER (filtered_stream), CAMEL_MIME_FILTER (pgp_filter)); g_object_unref (pgp_filter); /* Pass through the filters that have been setup */ dw = camel_medium_get_content ((CamelMedium *) part); camel_data_wrapper_decode_to_stream_sync ( dw, (CamelStream *) filtered_stream, cancellable, NULL); camel_stream_flush ((CamelStream *) filtered_stream, cancellable, NULL); g_object_unref (filtered_stream); /* Create a new text/plain MIME part containing the signed * content preserving the original part's Content-Type params. */ content_type = camel_mime_part_get_content_type (part); type = camel_content_type_format (content_type); content_type = camel_content_type_decode (type); g_free (type); g_free (content_type->type); content_type->type = g_strdup ("text"); g_free (content_type->subtype); content_type->subtype = g_strdup ("plain"); type = camel_content_type_format (content_type); camel_content_type_unref (content_type); ba = camel_stream_mem_get_byte_array ((CamelStreamMem *) ostream); opart = camel_mime_part_new (); camel_mime_part_set_content (opart, (gchar *) ba->data, ba->len, type); g_free (type); len = part_id->len; g_string_append (part_id, ".inlinepgp_signed"); e_mail_parser_parse_part ( parser, opart, part_id, cancellable, &work_queue); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".inlinepgp_signed.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_SIGNED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } /* Clean Up */ camel_cipher_validity_free (valid); g_object_unref (opart); g_object_unref (ostream); g_object_unref (cipher); return TRUE; }
static gboolean empe_mp_signed_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelMimePart *cpart = NULL; CamelMultipart *multipart; CamelCipherContext *cipher = NULL; CamelContentType *content_type; CamelSession *session; guint32 validity_type; CamelCipherValidity *valid; const gchar *protocol = NULL; GError *local_error = NULL; gint i, nparts, len; gboolean secured; /* If the part is application/pgp-signature sub-part then skip it. */ if (!CAMEL_IS_MULTIPART (part)) { content_type = camel_mime_part_get_content_type (part); if (camel_content_type_is ( content_type, "application", "pgp-signature")) { return TRUE; } } multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); if (CAMEL_IS_MULTIPART_SIGNED (multipart)) { cpart = camel_multipart_get_part ( multipart, CAMEL_MULTIPART_SIGNED_CONTENT); } if (cpart == NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse MIME message. " "Displaying as source.")); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); return TRUE; } content_type = camel_data_wrapper_get_mime_type_field ( CAMEL_DATA_WRAPPER (multipart)); if (content_type != NULL) protocol = camel_content_type_param (content_type, "protocol"); session = e_mail_parser_get_session (parser); /* FIXME: Should be done via a plugin interface */ /* FIXME: duplicated in em-format-html-display.c */ if (protocol != NULL) { #ifdef ENABLE_SMIME if (g_ascii_strcasecmp ("application/x-pkcs7-signature", protocol) == 0 || g_ascii_strcasecmp ("application/pkcs7-signature", protocol) == 0) { cipher = camel_smime_context_new (session); validity_type = E_MAIL_PART_VALIDITY_SMIME; } else { #endif if (g_ascii_strcasecmp ("application/pgp-signature", protocol) == 0) { cipher = camel_gpg_context_new (session); validity_type = E_MAIL_PART_VALIDITY_PGP; } #ifdef ENABLE_SMIME } #endif } if (cipher == NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Unsupported signature format")); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); return TRUE; } valid = camel_cipher_context_verify_sync ( cipher, part, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Error verifying signature: %s"), local_error->message); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); g_object_unref (cipher); g_error_free (local_error); return TRUE; } nparts = camel_multipart_get_number (multipart); secured = FALSE; len = part_id->len; for (i = 0; i < nparts; i++) { GQueue work_queue = G_QUEUE_INIT; GList *head, *link; CamelMimePart *subpart; subpart = camel_multipart_get_part (multipart, i); g_string_append_printf (part_id, ".signed.%d", i); g_warn_if_fail (e_mail_parser_parse_part ( parser, subpart, part_id, cancellable, &work_queue)); g_string_truncate (part_id, len); if (!secured) secured = e_mail_part_is_secured (subpart); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); } e_queue_transfer (&work_queue, out_mail_parts); } /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself. */ if (!secured) { GQueue work_queue = G_QUEUE_INIT; EMailPart *mail_part; g_string_append (part_id, ".signed.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, validity_type | E_MAIL_PART_VALIDITY_SIGNED); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } camel_cipher_validity_free (valid); g_object_unref (cipher); return TRUE; }
static CamelMimeMessage * mail_attachment_handler_get_selected_message (EAttachmentHandler *handler) { EAttachment *attachment; EAttachmentView *view; CamelMimePart *mime_part; CamelMimeMessage *message = NULL; CamelDataWrapper *outer_wrapper; CamelContentType *outer_content_type; CamelDataWrapper *inner_wrapper; CamelContentType *inner_content_type; GList *selected; gboolean inner_and_outer_content_types_match; view = e_attachment_handler_get_view (handler); selected = e_attachment_view_get_selected_attachments (view); g_return_val_if_fail (g_list_length (selected) == 1, NULL); attachment = E_ATTACHMENT (selected->data); mime_part = e_attachment_ref_mime_part (attachment); outer_wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); outer_content_type = camel_data_wrapper_get_mime_type_field (outer_wrapper); if (!camel_content_type_is (outer_content_type, "message", "rfc822")) goto exit; inner_wrapper = camel_medium_get_content (CAMEL_MEDIUM (outer_wrapper)); inner_content_type = camel_data_wrapper_get_mime_type_field (inner_wrapper); inner_and_outer_content_types_match = camel_content_type_is ( inner_content_type, outer_content_type->type, outer_content_type->subtype); if (!inner_and_outer_content_types_match) { CamelStream *mem; gboolean success; /* Create a message copy in case the inner content * type doesn't match the mime_part's content type, * which can happen for multipart/digest, where it * confuses the formatter on reply, which skips all * rfc822 subparts. */ mem = camel_stream_mem_new (); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (outer_wrapper), mem, NULL, NULL); g_seekable_seek ( G_SEEKABLE (mem), 0, G_SEEK_SET, NULL, NULL); message = camel_mime_message_new (); success = camel_data_wrapper_construct_from_stream_sync ( CAMEL_DATA_WRAPPER (message), mem, NULL, NULL); if (!success) g_clear_object (&message); g_object_unref (mem); } exit: if (message == NULL) message = g_object_ref (outer_wrapper); g_clear_object (&mime_part); g_list_free_full (selected, (GDestroyNotify) g_object_unref); return message; }
static gpointer worker (gpointer d) { struct _threadinfo *info = d; gint i, j, id = info->id; gchar *sub, *content; GPtrArray *res; CamelMimeMessage *msg; GError *error = NULL; /* we add a message, search for it, twiddle some flags, delete it */ /* and flat out */ for (i = 0; i < MAX_MESSAGES; i++) { test_add_message (info->folder, id + i); sub = g_strdup_printf ("(match-all (header-contains \"subject\" \"message %08x subject\"))", id + i); push ("searching for message %d\n\tusing: %s", id + i, sub); res = camel_folder_search_by_expression (info->folder, sub, NULL, &error); check_msg (error == NULL, "%s", error->message); check_msg (res->len == 1, "res->len = %d", res->len); g_clear_error (&error); pull (); push ("getting message '%s'", res->pdata[0]); msg = camel_folder_get_message_sync ( info->folder, (gchar *) res->pdata[0], NULL, &error); check_msg (error == NULL, "%s", error->message); g_clear_error (&error); pull (); content = g_strdup_printf ("Test message %08x contents\n\n", id + i); push ("comparing content '%s': '%s'", res->pdata[0], content); test_message_compare_content (camel_medium_get_content ((CamelMedium *) msg), content, strlen (content)); test_free (content); pull (); push ("deleting message, cleanup"); j = (100.0 * rand () / (RAND_MAX + 1.0)); if (j <= 70) { camel_folder_delete_message (info->folder, res->pdata[0]); } camel_folder_search_free (info->folder, res); res = NULL; test_free (sub); check_unref (msg, 1); pull (); /* about 1-in 100 calls will expunge */ j = (200.0 * rand () / (RAND_MAX + 1.0)); if (j <= 2) { push ("expunging folder"); camel_folder_expunge_sync (info->folder, NULL, &error); check_msg (error == NULL, "%s", error->message); pull (); } } return info; }
static gboolean empe_message_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { GQueue work_queue = G_QUEUE_INIT; CamelContentType *ct; EMailPart *mail_part; gchar *mime_type; /* Headers */ e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.headers", cancellable, out_mail_parts); ct = camel_mime_part_get_content_type (part); mime_type = camel_content_type_simple (ct); if (camel_content_type_is (ct, "message", "*")) { /* get mime type of the content of the message, * instead of using a generic message/rfc822 */ CamelDataWrapper *content; content = camel_medium_get_content (CAMEL_MEDIUM (part)); if (content) { ct = camel_data_wrapper_get_mime_type_field (content); g_free (mime_type); mime_type = camel_content_type_simple (ct); } } /* Actual message body */ e_mail_parser_parse_part_as ( parser, part, part_id, mime_type, cancellable, &work_queue); /* If the EMailPart representing the message body is marked as an * attachment, wrap it as such so it gets added to the attachment * bar but also set the "force_inline" flag since it doesn't make * sense to collapse the message body if we can render it. */ mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL && !E_IS_MAIL_PART_ATTACHMENT (mail_part)) { if (e_mail_part_get_is_attachment (mail_part)) { e_mail_parser_wrap_as_attachment ( parser, part, part_id, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) mail_part->force_inline = TRUE; } } e_queue_transfer (&work_queue, out_mail_parts); g_free (mime_type); return TRUE; }
static gboolean empe_mp_digest_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelMultipart *mp; gint i, nparts, len; mp = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part); if (!CAMEL_IS_MULTIPART (mp)) return e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); len = part_id->len; nparts = camel_multipart_get_number (mp); for (i = 0; i < nparts; i++) { CamelMimePart *subpart; CamelContentType *ct; gchar *cts; subpart = camel_multipart_get_part (mp, i); if (!subpart) continue; g_string_append_printf (part_id, ".digest.%d", i); ct = camel_mime_part_get_content_type (subpart); /* According to RFC this shouldn't happen, but who knows... */ if (ct && !camel_content_type_is (ct, "message", "rfc822")) { cts = camel_content_type_simple (ct); e_mail_parser_parse_part_as ( parser, subpart, part_id, cts, cancellable, out_mail_parts); g_free (cts); } else { GQueue work_queue = G_QUEUE_INIT; EMailPart *mail_part; gboolean wrap_as_attachment; e_mail_parser_parse_part_as ( parser, subpart, part_id, "message/rfc822", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); wrap_as_attachment = (mail_part != NULL) && !e_mail_part_get_is_attachment (mail_part); /* Force the message to be collapsable */ if (wrap_as_attachment) e_mail_parser_wrap_as_attachment ( parser, subpart, part_id, &work_queue); mail_part = g_queue_peek_head (&work_queue); /* Force the message to be expanded */ if (mail_part != NULL) mail_part->force_inline = TRUE; e_queue_transfer (&work_queue, out_mail_parts); } g_string_truncate (part_id, len); } return TRUE; }
static gboolean emfe_image_format (EMailFormatterExtension *extension, EMailFormatter *formatter, EMailFormatterContext *context, EMailPart *part, GOutputStream *stream, GCancellable *cancellable) { gchar *content; CamelMimePart *mime_part; CamelDataWrapper *dw; GBytes *bytes; GOutputStream *raw_content; if (g_cancellable_is_cancelled (cancellable)) return FALSE; mime_part = e_mail_part_ref_mime_part (part); dw = camel_medium_get_content (CAMEL_MEDIUM (mime_part)); g_return_val_if_fail (dw, FALSE); raw_content = g_memory_output_stream_new_resizable (); camel_data_wrapper_decode_to_output_stream_sync ( dw, raw_content, cancellable, NULL); g_output_stream_close (raw_content, NULL, NULL); bytes = g_memory_output_stream_steal_as_bytes ( G_MEMORY_OUTPUT_STREAM (raw_content)); if (context->mode == E_MAIL_FORMATTER_MODE_RAW) { if (!e_mail_formatter_get_animate_images (formatter)) { gchar *buff; gsize len; e_mail_part_animation_extract_frame ( bytes, &buff, &len); g_output_stream_write_all ( stream, buff, len, NULL, cancellable, NULL); g_free (buff); } else { gconstpointer data; gsize size; data = g_bytes_get_data (bytes, &size); g_output_stream_write_all ( stream, data, size, NULL, cancellable, NULL); } } else { gchar *buffer; const gchar *mime_type; if (!e_mail_formatter_get_animate_images (formatter)) { gchar *buff; gsize len; e_mail_part_animation_extract_frame ( bytes, &buff, &len); content = g_base64_encode ((guchar *) buff, len); g_free (buff); } else { gconstpointer data; gsize size; data = g_bytes_get_data (bytes, &size); content = g_base64_encode (data, size); } mime_type = e_mail_part_get_mime_type (part); if (mime_type == NULL) mime_type = "image/*"; /* The image is already base64-encrypted so we can directly * paste it to the output */ buffer = g_strdup_printf ( "<img src=\"data:%s;base64,%s\" " " style=\"max-width: 100%%;\" />", mime_type, content); g_output_stream_write_all ( stream, buffer, strlen (buffer), NULL, cancellable, NULL); g_free (buffer); g_free (content); } g_bytes_unref (bytes); g_object_unref (raw_content); g_object_unref (mime_part); return TRUE; }
static gboolean empe_mp_encrypted_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelCipherContext *context; const gchar *protocol; CamelMimePart *opart; CamelCipherValidity *valid; CamelMultipartEncrypted *mpe; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; GError *local_error = NULL; gint len; mpe = (CamelMultipartEncrypted *) camel_medium_get_content ((CamelMedium *) part); if (!CAMEL_IS_MULTIPART_ENCRYPTED (mpe)) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse MIME message. " "Displaying as source.")); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution/source", cancellable, out_mail_parts); return TRUE; } /* Currently we only handle RFC2015-style PGP encryption. */ protocol = camel_content_type_param ( ((CamelDataWrapper *) mpe)->mime_type, "protocol"); if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) { e_mail_parser_error ( parser, out_mail_parts, _("Unsupported encryption type for multipart/encrypted")); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); return TRUE; } context = camel_gpg_context_new (e_mail_parser_get_session (parser)); opart = camel_mime_part_new (); valid = camel_cipher_context_decrypt_sync ( context, part, opart, cancellable, &local_error); e_mail_part_preserve_charset_in_content_type (part, opart); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse PGP/MIME message: %s"), local_error->message); e_mail_parser_parse_part_as ( parser, part, part_id, "multipart/mixed", cancellable, out_mail_parts); g_object_unref (opart); g_object_unref (context); g_error_free (local_error); return TRUE; } len = part_id->len; g_string_append (part_id, ".encrypted"); g_warn_if_fail (e_mail_parser_parse_part ( parser, opart, part_id, cancellable, &work_queue)); g_string_truncate (part_id, len); head = g_queue_peek_head_link (&work_queue); /* Update validity of all encrypted sub-parts */ for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); /* Add a widget with details about the encryption, but only when * the decrypted part isn't itself secured, in that case it has * created the button itself. */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".encrypted.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } camel_cipher_validity_free (valid); /* TODO: Make sure when we finalize this part, it is zero'd out */ g_object_unref (opart); g_object_unref (context); return TRUE; }
static gboolean empe_inlinepgp_encrypted_parse (EMailParserExtension *extension, EMailParser *parser, CamelMimePart *part, GString *part_id, GCancellable *cancellable, GQueue *out_mail_parts) { CamelCipherContext *cipher; CamelCipherValidity *valid; CamelMimePart *opart; CamelDataWrapper *dw; gchar *mime_type; gint len; GQueue work_queue = G_QUEUE_INIT; GList *head, *link; GError *local_error = NULL; if (g_cancellable_is_cancelled (cancellable)) return FALSE; cipher = camel_gpg_context_new (e_mail_parser_get_session (parser)); opart = camel_mime_part_new (); /* Decrypt the message */ valid = camel_cipher_context_decrypt_sync ( cipher, part, opart, cancellable, &local_error); if (local_error != NULL) { e_mail_parser_error ( parser, out_mail_parts, _("Could not parse PGP message: %s"), local_error->message); g_error_free (local_error); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.source", cancellable, out_mail_parts); g_object_unref (cipher); g_object_unref (opart); return TRUE; } dw = camel_medium_get_content ((CamelMedium *) opart); mime_type = camel_data_wrapper_get_mime_type (dw); /* this ensures to show the 'opart' as inlined, if possible */ if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) { const gchar *snoop; snoop = e_mail_part_snoop_type (opart); if (snoop != NULL) { camel_data_wrapper_set_mime_type (dw, snoop); /* Set the MIME type on the 'opart' itself as well. * If it's "text/plain", then we want the TextPlain * parser extension to treat it as "text/plain" and * NOT wrap it as an attachment. */ camel_data_wrapper_set_mime_type ( CAMEL_DATA_WRAPPER (opart), snoop); } } e_mail_part_preserve_charset_in_content_type (part, opart); g_free (mime_type); /* Pass it off to the real formatter */ len = part_id->len; g_string_append (part_id, ".inlinepgp_encrypted"); g_warn_if_fail (e_mail_parser_parse_part_as ( parser, opart, part_id, camel_data_wrapper_get_mime_type (dw), cancellable, &work_queue)); g_string_truncate (part_id, len); head = g_queue_peek_head_link (&work_queue); for (link = head; link != NULL; link = g_list_next (link)) { EMailPart *mail_part = link->data; e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); } e_queue_transfer (&work_queue, out_mail_parts); /* Add a widget with details about the encryption, but only when * the encrypted isn't itself secured, in that case it has created * the button itself */ if (!e_mail_part_is_secured (opart)) { EMailPart *mail_part; g_string_append (part_id, ".inlinepgp_encrypted.button"); e_mail_parser_parse_part_as ( parser, part, part_id, "application/vnd.evolution.widget.secure-button", cancellable, &work_queue); mail_part = g_queue_peek_head (&work_queue); if (mail_part != NULL) e_mail_part_update_validity ( mail_part, valid, E_MAIL_PART_VALIDITY_ENCRYPTED | E_MAIL_PART_VALIDITY_PGP); e_queue_transfer (&work_queue, out_mail_parts); g_string_truncate (part_id, len); } /* Clean Up */ camel_cipher_validity_free (valid); g_object_unref (opart); g_object_unref (cipher); return TRUE; }
static void attachment_button_expand_drag_data_get_cb (EAttachmentButton *button, GdkDragContext *context, GtkSelectionData *selection, guint info, guint time) { EAttachmentView *view; EAttachment *attachment; gchar *mime_type = NULL; attachment = e_attachment_button_get_attachment (button); if (attachment != NULL) mime_type = e_attachment_dup_mime_type (attachment); if (mime_type != NULL) { gboolean processed = FALSE; GdkAtom atom; gchar *atom_name; atom = gtk_selection_data_get_target (selection); atom_name = gdk_atom_name (atom); if (g_strcmp0 (atom_name, mime_type) == 0) { CamelMimePart *mime_part; mime_part = e_attachment_ref_mime_part (attachment); if (mime_part != NULL) { CamelDataWrapper *wrapper; CamelStream *stream; GByteArray *buffer; buffer = g_byte_array_new (); stream = camel_stream_mem_new (); camel_stream_mem_set_byte_array ( CAMEL_STREAM_MEM (stream), buffer); wrapper = camel_medium_get_content ( CAMEL_MEDIUM (mime_part)); camel_data_wrapper_decode_to_stream_sync ( wrapper, stream, NULL, NULL); g_object_unref (stream); gtk_selection_data_set ( selection, atom, 8, buffer->data, buffer->len); processed = TRUE; g_byte_array_free (buffer, TRUE); g_object_unref (mime_part); } } g_free (atom_name); g_free (mime_type); if (processed) return; } view = e_attachment_button_get_view (button); e_attachment_view_drag_data_get ( view, context, selection, info, time); }