static void create_mime_message_cb (ESoapMessage *msg, gpointer user_data) { struct _create_mime_msg_data *create_data = user_data; CamelStream *mem, *filtered; CamelMimeFilter *filter; CamelContentType *content_type; GByteArray *bytes; gchar *base64; gint msgflag; guint32 message_camel_flags = 0; if (create_data->info) message_camel_flags = camel_message_info_flags (create_data->info); e_soap_message_start_element (msg, "Message", NULL, NULL); e_soap_message_start_element (msg, "MimeContent", NULL, NULL); /* This is horrid. We really need to extend ESoapMessage to allow us * to stream this directly rather than storing it in RAM. Which right * now we are doing about four times: the GByteArray in the mem stream, * then the base64 version, then the xmlDoc, then the soup request. */ camel_mime_message_set_best_encoding ( create_data->message, CAMEL_BESTENC_GET_ENCODING, CAMEL_BESTENC_8BIT); mem = camel_stream_mem_new (); filtered = camel_stream_filter_new (mem); filter = camel_mime_filter_crlf_new ( CAMEL_MIME_FILTER_CRLF_ENCODE, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY); camel_stream_filter_add (CAMEL_STREAM_FILTER (filtered), filter); g_object_unref (filter); camel_data_wrapper_write_to_stream_sync ( CAMEL_DATA_WRAPPER (create_data->message), filtered, NULL, NULL); camel_stream_flush (filtered, NULL, NULL); camel_stream_flush (mem, NULL, NULL); bytes = camel_stream_mem_get_byte_array (CAMEL_STREAM_MEM (mem)); base64 = g_base64_encode (bytes->data, bytes->len); g_object_unref (mem); g_object_unref (filtered); e_soap_message_write_string (msg, base64); g_free (base64); e_soap_message_end_element (msg); /* MimeContent */ content_type = camel_mime_part_get_content_type (CAMEL_MIME_PART (create_data->message)); if (content_type && camel_content_type_is (content_type, "multipart", "report") && camel_content_type_param (content_type, "report-type") && g_ascii_strcasecmp (camel_content_type_param (content_type, "report-type"), "disposition-notification") == 0) { /* it's a disposition notification reply, set ItemClass too */ e_soap_message_start_element (msg, "ItemClass", NULL, NULL); e_soap_message_write_string (msg, "REPORT.IPM.NOTE.IPNRN"); e_soap_message_end_element (msg); /* ItemClass */ } e_ews_message_write_string_parameter_with_attribute ( msg, "Importance", NULL, (message_camel_flags & CAMEL_MESSAGE_FLAGGED) != 0 ? "High" : "Normal", NULL, NULL); /* more MAPI crap. You can't just set the IsDraft property * here you have to use the MAPI MSGFLAG_UNSENT extended * property Further crap is that Exchange 2007 assumes when it * sees this property that you're setting the value to 0 * ... it never checks */ msgflag = MAPI_MSGFLAG_READ; /* draft or sent is always read */ if ((message_camel_flags & CAMEL_MESSAGE_DRAFT) != 0) msgflag |= MAPI_MSGFLAG_UNSENT; e_ews_message_add_extended_property_tag_int (msg, 0x0e07, msgflag); if ((message_camel_flags & (CAMEL_MESSAGE_FORWARDED | CAMEL_MESSAGE_ANSWERED)) != 0) { gint icon; icon = (message_camel_flags & CAMEL_MESSAGE_ANSWERED) != 0 ? 0x105 : 0x106; e_ews_message_add_extended_property_tag_int (msg, 0x1080, icon); } if (create_data->info) { const gchar *followup, *completed, *dueby; time_t completed_tt = (time_t) 0 , dueby_tt = (time_t) 0; /* follow-up flags */ followup = camel_message_info_user_tag (create_data->info, "follow-up"); completed = camel_message_info_user_tag (create_data->info, "completed-on"); dueby = camel_message_info_user_tag (create_data->info, "due-by"); if (followup && !*followup) followup = NULL; if (completed && *completed) completed_tt = camel_header_decode_date (completed, NULL); if (dueby && *dueby) dueby_tt = camel_header_decode_date (dueby, NULL); /* PidTagFlagStatus */ e_ews_message_add_extended_property_tag_int (msg, 0x1090, followup ? (completed_tt != (time_t) 0 ? 0x01 /* followupComplete */: 0x02 /* followupFlagged */) : 0x0); if (followup) { /* PidLidFlagRequest */ e_ews_message_add_extended_property_distinguished_tag_string (msg, "Common", 0x8530, followup); /* PidTagToDoItemFlags */ e_ews_message_add_extended_property_tag_int (msg, 0x0e2b, 1); } if (followup && completed_tt != (time_t) 0) { /* minute precision */ completed_tt = completed_tt - (completed_tt % 60); /* PidTagFlagCompleteTime */ e_ews_message_add_extended_property_tag_time (msg, 0x1091, completed_tt); /* PidLidTaskDateCompleted */ e_ews_message_add_extended_property_distinguished_tag_time (msg, "Task", 0x810f, completed_tt); /* PidLidTaskStatus */ e_ews_message_add_extended_property_distinguished_tag_int (msg, "Task", 0x8101, 2); /* PidLidPercentComplete */ e_ews_message_add_extended_property_distinguished_tag_double (msg, "Task", 0x8102, 1.0); /* PidLidTaskComplete */ e_ews_message_add_extended_property_distinguished_tag_boolean (msg, "Task", 0x811c, TRUE); } if (followup && dueby_tt != (time_t) 0 && completed_tt == (time_t) 0) { /* PidLidTaskStatus */ e_ews_message_add_extended_property_distinguished_tag_int (msg, "Task", 0x8101, 0); /* PidLidPercentComplete */ e_ews_message_add_extended_property_distinguished_tag_double (msg, "Task", 0x8102, 0.0); /* PidLidTaskDueDate */ e_ews_message_add_extended_property_distinguished_tag_time (msg, "Task", 0x8105, dueby_tt); /* PidLidTaskComplete */ e_ews_message_add_extended_property_distinguished_tag_boolean (msg, "Task", 0x811c, FALSE); } } if (create_data->recipients) { GHashTable *recip_to, *recip_cc, *recip_bcc; recip_to = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); recip_cc = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); recip_bcc = g_hash_table_new (camel_strcase_hash, camel_strcase_equal); filter_recipients (create_data->message, create_data->recipients, recip_to, recip_cc, recip_bcc); write_recipients (msg, "ToRecipients", recip_to); write_recipients (msg, "CcRecipients", recip_cc); write_recipients (msg, "BccRecipients", recip_bcc); g_hash_table_destroy (recip_to); g_hash_table_destroy (recip_cc); g_hash_table_destroy (recip_bcc); } e_ews_message_write_string_parameter_with_attribute ( msg, "IsRead", NULL, (message_camel_flags & CAMEL_MESSAGE_SEEN) != 0 ? "true" : "false", NULL, NULL); e_soap_message_end_element (msg); /* Message */ g_free (create_data); }
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; }