Exemplo n.º 1
0
static void
multipart_signed_set_mime_type_field (CamelDataWrapper *data_wrapper,
                                      CamelContentType *mime_type)
{
	CamelDataWrapperClass *data_wrapper_class;
	CamelMultipartSigned *mps = (CamelMultipartSigned *) data_wrapper;

	/* we snoop the mime type to get boundary and hash info */

	/* Chain up to parent's set_mime_type_field() method. */
	data_wrapper_class = CAMEL_DATA_WRAPPER_CLASS (camel_multipart_signed_parent_class);
	data_wrapper_class->set_mime_type_field (data_wrapper, mime_type);

	if (mime_type) {
		const gchar *micalg, *protocol;

		protocol = camel_content_type_param (mime_type, "protocol");
		g_free (mps->protocol);
		mps->protocol = g_strdup (protocol);

		micalg = camel_content_type_param (mime_type, "micalg");
		g_free (mps->micalg);
		mps->micalg = g_strdup (micalg);
	}
}
static const gchar *
multipart_get_boundary (CamelMultipart *multipart)
{
	CamelDataWrapper *cdw = CAMEL_DATA_WRAPPER (multipart);

	g_return_val_if_fail (cdw->mime_type != NULL, NULL);
	return camel_content_type_param (cdw->mime_type, "boundary");
}
Exemplo n.º 3
0
static gboolean
emqfe_headers_format (EMailFormatterExtension *extension,
                      EMailFormatter *formatter,
                      EMailFormatterContext *context,
                      EMailPart *part,
                      GOutputStream *stream,
                      GCancellable *cancellable)
{
	CamelContentType *ct;
	CamelMimePart *mime_part;
	const gchar *charset;
	GString *buffer;
	gchar **default_headers;
	guint ii, length = 0;

	g_return_val_if_fail (E_IS_MAIL_PART_HEADERS (part), FALSE);

	mime_part = e_mail_part_ref_mime_part (part);

	ct = camel_mime_part_get_content_type (mime_part);
	charset = camel_content_type_param (ct, "charset");
	charset = camel_iconv_charset_name (charset);

	buffer = g_string_new ("");

	/* dump selected headers */

	default_headers = e_mail_part_headers_dup_default_headers (
		E_MAIL_PART_HEADERS (part));
	if (default_headers != NULL)
		length = g_strv_length (default_headers);

	for (ii = 0; ii < length; ii++)
		emfqe_format_header (
			formatter, context, buffer, part,
			default_headers[ii], charset);

	g_strfreev (default_headers);

	g_string_append (buffer, HEADER_PREFIX);
	g_string_append (buffer, "<br>");
	g_string_append (buffer, HEADER_SUFFIX);

	g_output_stream_write_all (
		stream, buffer->str, buffer->len, NULL, cancellable, NULL);

	g_string_free (buffer, TRUE);

	g_object_unref (mime_part);

	return TRUE;
}
Exemplo n.º 4
0
static gint
multipart_signed_construct_from_parser (CamelMultipart *multipart,
                                        CamelMimeParser *mp)
{
	gint err;
	CamelContentType *content_type;
	CamelMultipartSigned *mps = (CamelMultipartSigned *) multipart;
	CamelDataWrapper *data_wrapper;
	GByteArray *byte_array;
	gchar *buf;
	gsize len;

	/* we *must not* be in multipart state, otherwise the mime parser will
	 * parse the headers which is a no no @#$@# stupid multipart/signed spec */
	g_assert (camel_mime_parser_state (mp) == CAMEL_MIME_PARSER_STATE_HEADER);

	/* All we do is copy it to a memstream */
	content_type = camel_mime_parser_content_type (mp);
	camel_multipart_set_boundary (multipart, camel_content_type_param (content_type, "boundary"));

	data_wrapper = CAMEL_DATA_WRAPPER (multipart);
	byte_array = camel_data_wrapper_get_byte_array (data_wrapper);

	/* Wipe any previous contents from the byte array. */
	g_byte_array_set_size (byte_array, 0);

	while (camel_mime_parser_step (mp, &buf, &len) != CAMEL_MIME_PARSER_STATE_BODY_END)
		g_byte_array_append (byte_array, (guint8 *) buf, len);

	mps->start1 = -1;
	if (mps->content) {
		g_object_unref (mps->content);
		mps->content = NULL;
	}
	if (mps->contentraw) {
		g_object_unref (mps->contentraw);
		mps->contentraw = NULL;
	}
	if (mps->signature) {
		g_object_unref (mps->signature);
		mps->signature = NULL;
	}

	err = camel_mime_parser_errno (mp);
	if (err != 0) {
		errno = err;
		return -1;
	} else
		return 0;
}
/* we snoop the mime type to get the protocol */
static void
set_mime_type_field (CamelDataWrapper *data_wrapper, CamelContentType *mime_type)
{
	CamelMultipartEncrypted *mpe = (CamelMultipartEncrypted *) data_wrapper;

	if (mime_type) {
		const char *protocol;

		protocol = camel_content_type_param (mime_type, "protocol");
		g_free (mpe->protocol);
		mpe->protocol = g_strdup (protocol);
	}

	((CamelDataWrapperClass *) parent_class)->set_mime_type_field (data_wrapper, mime_type);
}
static gint
multipart_construct_from_parser (CamelMultipart *multipart,
                                 CamelMimeParser *mp)
{
	gint err;
	CamelContentType *content_type;
	CamelMimePart *bodypart;
	gchar *buf;
	gsize len;

	g_assert (camel_mime_parser_state (mp) == CAMEL_MIME_PARSER_STATE_MULTIPART);

	/* FIXME: we should use a came-mime-mutlipart, not jsut a camel-multipart, but who cares */
	d(printf("Creating multi-part\n"));

	content_type = camel_mime_parser_content_type (mp);
	camel_multipart_set_boundary (multipart,
				     camel_content_type_param(content_type, "boundary"));

	while (camel_mime_parser_step (mp, &buf, &len) != CAMEL_MIME_PARSER_STATE_MULTIPART_END) {
		camel_mime_parser_unstep (mp);
		bodypart = camel_mime_part_new ();
		camel_mime_part_construct_from_parser_sync (
			bodypart, mp, NULL, NULL);
		camel_multipart_add_part (multipart, bodypart);
		g_object_unref (bodypart);
	}

	/* these are only return valid data in the MULTIPART_END state */
	camel_multipart_set_preface (multipart, camel_mime_parser_preface (mp));
	camel_multipart_set_postface (multipart, camel_mime_parser_postface (mp));

	err = camel_mime_parser_errno (mp);
	if (err != 0) {
		errno = err;
		return -1;
	} else
		return 0;
}
Exemplo n.º 7
0
static CamelSExpResult *
check_header (struct _CamelSExp *f,
              gint argc,
              struct _CamelSExpResult **argv,
              FilterMessageSearch *fms,
              camel_search_match_t how)
{
	gboolean matched = FALSE;
	CamelSExpResult *r;
	gint i;

	if (argc > 1 && argv[0]->type == CAMEL_SEXP_RES_STRING) {
		gchar *name = argv[0]->value.string;

		/* shortcut: a match for "" against any header always matches */
		for (i = 1; i < argc && !matched; i++)
			matched = argv[i]->type == CAMEL_SEXP_RES_STRING && argv[i]->value.string[0] == 0;

		if (g_ascii_strcasecmp (name, "x-camel-mlist") == 0) {
			const gchar *list = camel_message_info_mlist (fms->info);

			if (list) {
				for (i = 1; i < argc && !matched; i++) {
					if (argv[i]->type == CAMEL_SEXP_RES_STRING)
						matched = camel_search_header_match (list, argv[i]->value.string, how, CAMEL_SEARCH_TYPE_MLIST, NULL);
				}
			}
		} else if (fms->message || !check_header_in_message_info (fms->info, argc, argv, how, &matched)) {
			CamelMimeMessage *message;
			CamelMimePart *mime_part;
			struct _camel_header_raw *header;
			const gchar *charset = NULL;
			camel_search_t type = CAMEL_SEARCH_TYPE_ENCODED;
			CamelContentType *ct;

			message = camel_filter_search_get_message (fms, f);
			mime_part = CAMEL_MIME_PART (message);

			/* FIXME: what about Resent-To, Resent-Cc and Resent-From? */
			if (g_ascii_strcasecmp ("to", name) == 0 || g_ascii_strcasecmp ("cc", name) == 0 || g_ascii_strcasecmp ("from", name) == 0)
				type = CAMEL_SEARCH_TYPE_ADDRESS_ENCODED;
			else if (message) {
				ct = camel_mime_part_get_content_type (mime_part);
				if (ct) {
					charset = camel_content_type_param (ct, "charset");
					charset = camel_iconv_charset_name (charset);
				}
			}

			for (header = mime_part->headers; header && !matched; header = header->next) {
				/* empty name means any header */
				if (!name || !*name || !g_ascii_strcasecmp (header->name, name)) {
					for (i = 1; i < argc && !matched; i++) {
						if (argv[i]->type == CAMEL_SEXP_RES_STRING)
							matched = camel_search_header_match (header->value, argv[i]->value.string, how, type, charset);
					}
				}
			}
		}
	}

	r = camel_sexp_result_new (f, CAMEL_SEXP_RES_BOOL);
	r->value.boolean = matched;

	return r;
}
static gboolean
emqfe_text_plain_format (EMailFormatterExtension *extension,
                         EMailFormatter *formatter,
                         EMailFormatterContext *context,
                         EMailPart *part,
                         GOutputStream *stream,
                         GCancellable *cancellable)
{
	GOutputStream *filtered_stream;
	GOutputStream *temp_stream;
	CamelMimeFilter *filter;
	CamelMimePart *mime_part;
	CamelContentType *type;
	EMailFormatterQuoteContext *qf_context;
	CamelMimeFilterToHTMLFlags text_flags;
	const gchar *format;
	guint32 rgb = 0x737373;

	mime_part = e_mail_part_ref_mime_part (part);
	if (mime_part == NULL)
		return FALSE;

	qf_context = (EMailFormatterQuoteContext *) context;

	text_flags =
		CAMEL_MIME_FILTER_TOHTML_PRE |
		CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
		CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;

	/* XXX Should we define a separate EMailFormatter property
	 *     for using CAMEL_MIME_FILTER_TOHTML_QUOTE_CITATION? */
	if (e_mail_formatter_get_mark_citations (formatter))
		text_flags |= CAMEL_MIME_FILTER_TOHTML_QUOTE_CITATION;

	/* Check for RFC 2646 flowed text. */
	type = camel_mime_part_get_content_type (mime_part);
	if (camel_content_type_is (type, "text", "plain")
	    && (format = camel_content_type_param (type, "format"))
	    && !g_ascii_strcasecmp (format, "flowed"))
		text_flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;

	filtered_stream = g_object_ref (stream);

	if ((qf_context->qf_flags & E_MAIL_FORMATTER_QUOTE_FLAG_KEEP_SIG) == 0) {
		filter = e_mail_stripsig_filter_new (TRUE);
		temp_stream = camel_filter_output_stream_new (
			filtered_stream, filter);
		g_filter_output_stream_set_close_base_stream (
			G_FILTER_OUTPUT_STREAM (temp_stream), FALSE);
		g_object_unref (filtered_stream);
		filtered_stream = temp_stream;
		g_object_unref (filter);
	}

	filter = camel_mime_filter_tohtml_new (text_flags, rgb);
	temp_stream = camel_filter_output_stream_new (filtered_stream, filter);
	g_filter_output_stream_set_close_base_stream (
		G_FILTER_OUTPUT_STREAM (temp_stream), FALSE);
	g_object_unref (filtered_stream);
	filtered_stream = temp_stream;
	g_object_unref (filter);

	e_mail_formatter_format_text (
		formatter, part, filtered_stream, cancellable);

	g_output_stream_flush (filtered_stream, cancellable, NULL);
	g_object_unref (filtered_stream);

	g_object_unref (mime_part);

	return TRUE;
}
Exemplo n.º 9
0
static CamelCipherValidity *
sm_verify(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
{
	NSSCMSDecoderContext *dec;
	NSSCMSMessage *cmsg;
	CamelStreamMem *mem;
	CamelStream *constream = NULL;
	CamelCipherValidity *valid = NULL;
	CamelContentType *ct;
	const char *tmp;
	CamelMimePart *sigpart;
	CamelDataWrapper *dw;

	dw = camel_medium_get_content_object((CamelMedium *)ipart);
	ct = dw->mime_type;

	/* FIXME: we should stream this to the decoder */
	mem = (CamelStreamMem *)camel_stream_mem_new();

	if (camel_content_type_is(ct, "multipart", "signed")) {
		CamelMultipart *mps = (CamelMultipart *)dw;

		tmp = camel_content_type_param(ct, "protocol");
		if (!CAMEL_IS_MULTIPART_SIGNED(mps)
		    || tmp == NULL
		    || (g_ascii_strcasecmp(tmp, context->sign_protocol) != 0
			&& g_ascii_strcasecmp(tmp, "application/pkcs7-signature") != 0)) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
					     _("Cannot verify message signature: Incorrect message format"));
			goto fail;
		}

		constream = camel_multipart_signed_get_content_stream((CamelMultipartSigned *)mps, ex);
		if (constream == NULL)
			goto fail;

		sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
		if (sigpart == NULL) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
					     _("Cannot verify message signature: Incorrect message format"));
			goto fail;
		}
	} else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) {
		sigpart = ipart;
	} else {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
				     _("Cannot verify message signature: Incorrect message format"));
		goto fail;
	}

	dec = NSS_CMSDecoder_Start(NULL,
				   NULL, NULL, /* content callback     */
				   NULL, NULL, 	/* password callback    */
				   NULL, NULL); /* decrypt key callback */

	camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem);
	(void)NSS_CMSDecoder_Update(dec, (char *) mem->buffer->data, mem->buffer->len);
	cmsg = NSS_CMSDecoder_Finish(dec);
	if (cmsg == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed"));
		goto fail;
	}

	valid = sm_verify_cmsg(context, cmsg, constream, ex);

	NSS_CMSMessage_Destroy(cmsg);
fail:
	camel_object_unref(mem);
	if (constream)
		camel_object_unref(constream);

	return valid;
}
Exemplo n.º 10
0
/* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */
guint32
camel_smime_context_describe_part(CamelSMIMEContext *context, CamelMimePart *part)
{
	guint32 flags = 0;
	CamelContentType *ct;
	const char *tmp;

	if (!part)
		return flags;

	ct = camel_mime_part_get_content_type(part);

	if (camel_content_type_is(ct, "multipart", "signed")) {
		tmp = camel_content_type_param(ct, "protocol");
		if (tmp &&
		    (g_ascii_strcasecmp(tmp, ((CamelCipherContext *)context)->sign_protocol) == 0
		     || g_ascii_strcasecmp(tmp, "application/pkcs7-signature") == 0))
			flags = CAMEL_SMIME_SIGNED;
	} else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) {
		CamelStreamMem *istream;
		NSSCMSMessage *cmsg;
		NSSCMSDecoderContext *dec;

		/* FIXME: stream this to the decoder incrementally */
		istream = (CamelStreamMem *)camel_stream_mem_new();
		camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)istream);
		camel_stream_reset((CamelStream *)istream);

		dec = NSS_CMSDecoder_Start(NULL,
					   NULL, NULL,
					   NULL, NULL,	/* password callback    */
					   NULL, NULL); /* decrypt key callback */

		NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len);
		camel_object_unref(istream);

		cmsg = NSS_CMSDecoder_Finish(dec);
		if (cmsg) {
			if (NSS_CMSMessage_IsSigned(cmsg)) {
				printf("message is signed\n");
				flags |= CAMEL_SMIME_SIGNED;
			}

			if (NSS_CMSMessage_IsEncrypted(cmsg)) {
				printf("message is encrypted\n");
				flags |= CAMEL_SMIME_ENCRYPTED;
			}
#if 0
			if (NSS_CMSMessage_ContainsCertsOrCrls(cmsg)) {
				printf("message contains certs or crls\n");
				flags |= CAMEL_SMIME_CERTS;
			}
#endif
			NSS_CMSMessage_Destroy(cmsg);
		} else {
			printf("Message could not be parsed\n");
		}
	}

	return flags;
}
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;
}
Exemplo n.º 12
0
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);
}
/* FIXME: check format of fields. */
static gboolean
process_header (CamelMedium *medium,
                const gchar *name,
                const gchar *value)
{
	CamelHeaderType header_type;
	CamelMimeMessage *message = CAMEL_MIME_MESSAGE (medium);
	CamelInternetAddress *addr;
	const gchar *charset;
	gchar *unfolded;

	header_type = (CamelHeaderType) g_hash_table_lookup (header_name_table, name);
	switch (header_type) {
	case HEADER_FROM:
		addr = camel_internet_address_new ();
		unfolded = camel_header_unfold (value);
		if (camel_address_decode ((CamelAddress *) addr, unfolded) <= 0) {
			g_object_unref (addr);
		} else {
			if (message->from)
				g_object_unref (message->from);
			message->from = addr;
		}
		g_free (unfolded);
		break;
	case HEADER_REPLY_TO:
		addr = camel_internet_address_new ();
		unfolded = camel_header_unfold (value);
		if (camel_address_decode ((CamelAddress *) addr, unfolded) <= 0) {
			g_object_unref (addr);
		} else {
			if (message->reply_to)
				g_object_unref (message->reply_to);
			message->reply_to = addr;
		}
		g_free (unfolded);
		break;
	case HEADER_SUBJECT:
		g_free (message->subject);
		if (((CamelDataWrapper *) message)->mime_type) {
			charset = camel_content_type_param (((CamelDataWrapper *) message)->mime_type, "charset");
			charset = camel_iconv_charset_name (charset);
		} else
			charset = NULL;

		unfolded = camel_header_unfold (value);
		message->subject = g_strstrip (camel_header_decode_string (unfolded, charset));
		g_free (unfolded);
		break;
	case HEADER_TO:
	case HEADER_CC:
	case HEADER_BCC:
	case HEADER_RESENT_TO:
	case HEADER_RESENT_CC:
	case HEADER_RESENT_BCC:
		addr = g_hash_table_lookup (message->recipients, name);
		if (value) {
			unfolded = camel_header_unfold (value);
			camel_address_decode (CAMEL_ADDRESS (addr), unfolded);
			g_free (unfolded);
		} else {
			camel_address_remove (CAMEL_ADDRESS (addr), -1);
		}
		return FALSE;
	case HEADER_DATE:
		if (value) {
			message->date = camel_header_decode_date (value, &message->date_offset);
		} else {
			message->date = CAMEL_MESSAGE_DATE_CURRENT;
			message->date_offset = 0;
		}
		break;
	case HEADER_MESSAGE_ID:
		g_free (message->message_id);
		if (value)
			message->message_id = camel_header_msgid_decode (value);
		else
			message->message_id = NULL;
		break;
	default:
		return FALSE;
	}

	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;
}