void sipe_mime_parts_foreach(const gchar *type, const gchar *body, sipe_mime_parts_cb callback, gpointer user_data) { gchar *doc = g_strdup_printf("Content-Type: %s\r\n\r\n%s", type, body); GMimeStream *stream = g_mime_stream_mem_new_with_buffer(doc, strlen(doc)); if (stream) { GMimeParser *parser = g_mime_parser_new_with_stream(stream); GMimeMultipart *multipart = (GMimeMultipart *)g_mime_parser_construct_part(parser); if (multipart) { struct gmime_callback_data cd = {callback, user_data}; SIPE_DEBUG_INFO("sipe_mime_parts_foreach: %d parts", g_mime_multipart_get_count(multipart)); g_mime_multipart_foreach(multipart, gmime_callback, &cd); g_object_unref(multipart); } g_object_unref(parser); g_object_unref(stream); } g_free(doc); }
gboolean g_mime_gpgme_mps_sign(GMimeMultipartSigned * mps, GMimeObject * content, const gchar * userid, gpgme_protocol_t protocol, GtkWindow * parent, GError ** err) { GMimeStream *stream; GMimeStream *filtered; GMimeStream *sigstream; GMimeFilter *filter; GMimeContentType *content_type; GMimeDataWrapper *wrapper; GMimeParser *parser; GMimePart *signature; gchar *micalg; const gchar *proto_type; const gchar *sig_subtype; gpgme_hash_algo_t hash_algo; g_return_val_if_fail(GMIME_IS_MULTIPART_SIGNED(mps), FALSE); g_return_val_if_fail(GMIME_IS_OBJECT(content), FALSE); /* Prepare all the parts for signing... */ sign_prepare(content); /* get the cleartext */ stream = g_mime_stream_mem_new(); filtered = g_mime_stream_filter_new(stream); /* Note: see rfc3156, section 3 - second note */ filter = g_mime_filter_from_new(GMIME_FILTER_FROM_MODE_ARMOR); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); /* Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156) */ filter = g_mime_filter_strip_new(); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); g_mime_object_write_to_stream(content, filtered); g_mime_stream_flush(filtered); g_object_unref(filtered); g_mime_stream_reset(stream); /* Note: see rfc2015 or rfc3156, section 5.1 */ filtered = g_mime_stream_filter_new(stream); filter = g_mime_filter_crlf_new(TRUE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered), filter); g_object_unref(filter); /* construct the signature stream */ sigstream = g_mime_stream_mem_new(); /* sign the content stream */ hash_algo = libbalsa_gpgme_sign(userid, filtered, sigstream, protocol, FALSE, parent, err); g_object_unref(filtered); if (hash_algo == GPGME_MD_NONE) { g_object_unref(sigstream); g_object_unref(stream); return FALSE; } g_mime_stream_reset(sigstream); g_mime_stream_reset(stream); /* set the multipart/signed protocol and micalg */ content_type = g_mime_object_get_content_type(GMIME_OBJECT(mps)); if (protocol == GPGME_PROTOCOL_OpenPGP) { micalg = g_strdup_printf("PGP-%s", gpgme_hash_algo_name(hash_algo)); proto_type = "application/pgp-signature"; sig_subtype = "pgp-signature"; } else { micalg = g_strdup(gpgme_hash_algo_name(hash_algo)); proto_type = "application/pkcs7-signature"; sig_subtype = "pkcs7-signature"; } g_mime_content_type_set_parameter(content_type, "micalg", micalg); g_free(micalg); g_mime_content_type_set_parameter(content_type, "protocol", proto_type); g_mime_multipart_set_boundary(GMIME_MULTIPART(mps), NULL); /* construct the content part */ parser = g_mime_parser_new_with_stream(stream); content = g_mime_parser_construct_part(parser); g_object_unref(stream); g_object_unref(parser); /* construct the signature part */ signature = g_mime_part_new_with_type("application", sig_subtype); wrapper = g_mime_data_wrapper_new(); g_mime_data_wrapper_set_stream(wrapper, sigstream); g_mime_part_set_content_object(signature, wrapper); g_object_unref(sigstream); g_object_unref(wrapper); /* FIXME: temporary hack, this info should probably be set in * the CipherContext class - maybe ::sign can take/output a * GMimePart instead. */ if (protocol == GPGME_PROTOCOL_CMS) { g_mime_part_set_content_encoding(signature, GMIME_CONTENT_ENCODING_BASE64); g_mime_part_set_filename(signature, "smime.p7m"); } /* save the content and signature parts */ /* FIXME: make sure there aren't any other parts?? */ g_mime_multipart_add(GMIME_MULTIPART(mps), content); g_mime_multipart_add(GMIME_MULTIPART(mps), (GMimeObject *) signature); g_object_unref(signature); g_object_unref(content); return TRUE; }
GMimeObject * g_mime_gpgme_mpe_decrypt(GMimeMultipartEncrypted * mpe, GMimeGpgmeSigstat ** signature, GtkWindow * parent, GError ** err) { GMimeObject *decrypted, *version, *encrypted; GMimeStream *stream, *ciphertext; GMimeStream *filtered_stream; GMimeContentType *mime_type; GMimeGpgmeSigstat *sigstat; GMimeDataWrapper *wrapper; GMimeFilter *crlf_filter; GMimeParser *parser; const char *protocol; char *content_type; g_return_val_if_fail(GMIME_IS_MULTIPART_ENCRYPTED(mpe), NULL); if (signature && *signature) { g_object_unref(G_OBJECT(*signature)); *signature = NULL; } protocol = g_mime_object_get_content_type_parameter(GMIME_OBJECT(mpe), "protocol"); /* make sure the protocol is present and matches the cipher encrypt protocol */ if (!protocol || g_ascii_strcasecmp("application/pgp-encrypted", protocol) != 0) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, _ ("Cannot decrypt multipart/encrypted part: unsupported encryption protocol “%s”."), protocol ? protocol : _("(none)")); return NULL; } version = g_mime_multipart_get_part(GMIME_MULTIPART(mpe), GMIME_MULTIPART_ENCRYPTED_VERSION); /* make sure the protocol matches the version part's content-type */ content_type = g_mime_content_type_to_string(version->content_type); if (g_ascii_strcasecmp(content_type, protocol) != 0) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: content-type does not match protocol.")); g_free(content_type); return NULL; } g_free(content_type); /* get the encrypted part and check that it is of type application/octet-stream */ encrypted = g_mime_multipart_get_part(GMIME_MULTIPART(mpe), GMIME_MULTIPART_ENCRYPTED_CONTENT); mime_type = g_mime_object_get_content_type(encrypted); if (!g_mime_content_type_is_type (mime_type, "application", "octet-stream")) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: unexpected content type")); return NULL; } /* get the ciphertext stream */ wrapper = g_mime_part_get_content_object(GMIME_PART(encrypted)); ciphertext = g_mime_data_wrapper_get_decoded_stream(wrapper); g_mime_stream_reset(ciphertext); stream = g_mime_stream_mem_new(); filtered_stream = g_mime_stream_filter_new(stream); crlf_filter = g_mime_filter_crlf_new(FALSE, FALSE); g_mime_stream_filter_add(GMIME_STREAM_FILTER(filtered_stream), crlf_filter); g_object_unref(crlf_filter); /* get the cleartext */ sigstat = libbalsa_gpgme_decrypt(ciphertext, filtered_stream, GPGME_PROTOCOL_OpenPGP, parent, err); if (!sigstat) { g_object_unref(filtered_stream); g_object_unref(ciphertext); g_object_unref(stream); return NULL; } g_mime_stream_flush(filtered_stream); g_object_unref(filtered_stream); g_object_unref(ciphertext); g_mime_stream_reset(stream); parser = g_mime_parser_new(); g_mime_parser_init_with_stream(parser, stream); g_object_unref(stream); decrypted = g_mime_parser_construct_part(parser); g_object_unref(parser); if (!decrypted) { g_set_error(err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR, "%s", _ ("Cannot decrypt multipart/encrypted part: failed to parse decrypted content")); g_object_unref(G_OBJECT(sigstat)); return NULL; } /* cache the decrypted part */ if (signature) { if (sigstat->status != GPG_ERR_NOT_SIGNED) *signature = sigstat; else g_object_unref(G_OBJECT(sigstat)); } return decrypted; }