[gmime] Make GMimeMultipartSigned/Encrypted easier to use



commit 1ed4d589ea96999e09ae8a6397d6e9a1f62ba74b
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Sat Mar 11 16:23:57 2017 -0500

    Make GMimeMultipartSigned/Encrypted easier to use

 PORTING                           |    8 +++
 README.md                         |  117 ++++++++++++++++++++++++++++++++++
 docs/reference/changes-3.0.sgml   |    2 +
 gmime/gmime-multipart-encrypted.c |  126 ++++++++++++++++++-------------------
 gmime/gmime-multipart-encrypted.h |   10 +--
 gmime/gmime-multipart-signed.c    |   89 +++++++++++++-------------
 gmime/gmime-multipart-signed.h    |    6 +-
 tests/test-pgpmime.c              |   90 ++++++++++++++------------
 tests/test-smime.c                |    8 +--
 9 files changed, 288 insertions(+), 168 deletions(-)
---
diff --git a/PORTING b/PORTING
index e8ebe54..4669de7 100644
--- a/PORTING
+++ b/PORTING
@@ -118,6 +118,14 @@ Porting from GMime 2.6 to GMime 3.0
 - g_mime_part_[get,set]_content_object() have been renamed to
   g_mime_part_[get,set]_content().
 
+- g_mime_multipart_encrypted_encrypt() no longer takes a GMimeMultipartEncrypted
+  argument nor does it return int. Instead, this function now returns a newly
+  allocated GMimeMultipartEncrypted.
+
+- g_mime_multipart_signed_sign() no longer takes a GMimeMultipartSigned
+  argument nor does it return int. Instead, this function now returns a newly
+  allocated GMimeMultipartSigned.
+
 
 Porting from GMime 2.4 to GMime 2.6
 -----------------------------------
diff --git a/README.md b/README.md
index 579dd2c..6a23ec2 100644
--- a/README.md
+++ b/README.md
@@ -355,6 +355,123 @@ g_mime_message_set_mime_part (message, (GMimeObject *) mixed);
 g_object_unref (mixed);
 ```
 
+### Encrypting Messages with S/MIME
+
+S/MIME uses an `application/pkcs7-mime` MIME part to encapsulate encrypted content (as well as other things).
+
+```c
+GMimeApplicationPkcs7Mime *encrypted;
+GMimeMessage *message;
+GError *err = NULL;
+GMimeObject *body;
+GPtrArray *rcpts;
+
+message = g_mime_message_new (TRUE);
+g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey friends com");
+g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice wonderland com");
+g_mime_message_set_subject (message, "How you doin?", NULL);
+
+/* create our message body (perhaps a multipart/mixed with the message text and some
+ * image attachments, for example) */
+body = CreateMessageBody ();
+
+/* create a list of key ids to encrypt to */
+rcpts = g_ptr_array_new ();
+g_ptr_array_add (rcpts, "alice wonderland com"); // or use her fingerprint
+
+/* now to encrypt our message body */
+if (!(encrypted = g_mime_application_pkcs7_mime_encrypt (body, GMIME_ENCRYPT_FLAGS_NONE, rcpts, &err))) {
+    fprintf (stderr, "encrypt failed: %s\n", err->message);
+    g_object_unref (body);
+    g_error_free (err);
+    return;
+}
+
+g_object_unref (body);
+
+g_mime_message_set_mime_part (message, encrypted);
+g_object_unref (encrypted);
+```
+
+### Decrypting S/MIME Messages
+
+As mentioned earlier, S/MIME uses an `application/pkcs7-mime` part with an "smime-type" parameter with a 
value of
+"enveloped-data" to encapsulate the encrypted content.
+
+The first thing you must do is find the `GMimeApplicationPkcs7Mime` part (see the section on traversing MIME 
parts).
+
+```c
+if (GMIME_IS_APPLICATION_PKCS7_MIME (entity)) {
+    GMimeApplicationPkcs7Mime *pkcs7_mime = (GMimeApplicationPkcs7Mime *) entity;
+    GMimeSecureMimeType smime_type;
+
+    smime_type = g_mime_application_pkcs7_mime_get_smime_type (pkcs7_mime);
+    if (smime_type == GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA)
+        return g_mime_application_pkcs7_mime_decrypt (pkcs7_mime, GMIME_DECRYPT_FLAGS_NONE, NULL, NULL, 
&err);
+}
+```
+
+### Encrypting Messages with PGP/MIME
+
+Unlike S/MIME, PGP/MIME uses `multipart/encrypted` to encapsulate its encrypted data.
+
+```c
+GMimeMultipartEncrypted *encrypted;
+GMimeCryptoContext *ctx;
+GMimeMessage *message;
+GError *err = NULL;
+GMimeObject *body;
+GPtrArray *rcpts;
+
+message = g_mime_message_new (TRUE);
+g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_FROM, "Joey", "joey friends com");
+g_mime_message_add_mailbox (message, GMIME_ADDRESS_TYPE_TO, "Alice", "alice wonderland com");
+g_mime_message_set_subject (message, "How you doin?", NULL);
+
+/* create our message body (perhaps a multipart/mixed with the message text and some
+ * image attachments, for example) */
+body = CreateMessageBody ();
+
+/* create a list of key ids to encrypt to */
+rcpts = g_ptr_array_new ();
+g_ptr_array_add (rcpts, "alice wonderland com"); // or use her fingerprint
+
+/* now to encrypt our message body */
+ctx = g_mime_gpg_context_new ();
+
+encrypted = g_mime_multipart_encrypted_encrypt (ctx, body, FALSE, NULL, GMIME_DIGEST_ALGO_DEFAULT,
+     GMIME_ENCRYPT_FLAGS_NONE, rcpts, &err);
+g_ptr_array_free (rcpts, TRUE);
+g_object_unref (body);
+g_object_unref (ctx);
+
+if (encrypted == NULL) {
+    fprintf (stderr, "encrypt failed: %s\n", err->message);
+    g_error_free (err);
+    return;
+}
+
+g_mime_message_set_mime_part (message, encrypted);
+g_object_unref (encrypted);
+```
+
+### Decrypting PGP/MIME Messages
+
+As mentioned earlier, PGP/MIME uses a `multipart/encrypted` part to encapsulate the encrypted content.
+
+A `multipart/encrypted` contains exactly 2 parts: the first `GMimeObject` is the version information while 
the
+second `GMimeObject` is the actual encrypted content and will typically be an `application/octet-stream`.
+
+The first thing you must do is find the `GMimeMultipartEncrypted` part (see the section on traversing MIME 
parts).
+
+```c
+if (GMIME_IS_MULTIPART_ENCRYPTED (entity)) {
+    GMimeMultipartEncrypted *encrypted = (GMimeMultipartEncrypted *) entity;
+
+    return g_mime_multipart_encrypted_decrypt (encrypted, GMIME_DECRYPT_FLAGS_NONE, NULL, NULL, &err);
+}
+```
+
 ## Documentation
 
 This is the README file for GMime. Additional documentation related to
diff --git a/docs/reference/changes-3.0.sgml b/docs/reference/changes-3.0.sgml
index 64d3d10..d990eee 100644
--- a/docs/reference/changes-3.0.sgml
+++ b/docs/reference/changes-3.0.sgml
@@ -32,6 +32,8 @@
       <listitem><para><function>g_mime_crypto_context_verify()</function> no longer takes a 'digest' 
argument as it was unused (it was originally meant to be a hint but wasnever really needed).</para></listitem>
       <listitem><para><function>g_mime_multipart_signed_verify()</function> and 
<function>g_mime_multipart_encrypted_decrypt()</function> no longer take GMimeCryptoContext arguments. 
Instead, they instantiate their own contexts based on the protocol specified in the Content-Type header. 
These methods now also take a flags argument and in the case of the decrypt() method, it now also takes a 
session_key argument.</para></listitem>
       <listitem><para>GMimeSignatureStatus and GMimeSignatureErrors have been merged into a single bitfield 
(GMimeSignatureStatus) which mirrors gpgme_sigsum_t and thus 
<function>g_mime_signature_get_errors()</function> and <function>g_mime_signature_set_errors()</function> 
have been removed.</para></listitem>
+      <listitem><para><function>g_mime_multipart_encrypted_encrypt()</function> no longer takes a 
GMimeMultipartEncrypted argument nor does it return int. Instead, this function now returns a newly allocated 
GMimeMultipartEncrypted.</para></listitem>
+      <listitem><para><function>g_mime_multipart_signed_sign()</function> no longer takes a 
GMimeMultipartSigned argument nor does it return int. Instead, this function now returns a newly allocated 
GMimeMultipartSigned.</para></listitem>
     </itemizedlist>
     <para>Other API changes:</para>
       <listitem><para><function>g_mime_set_user_charsets()</function> and 
<function>g_mime_user_charsets()</function> have been removed. All encoding API's now have a way to specify a 
charset to use and all decoder API's take a GMimeParserOptions argument that allows for specifying fallback 
charsets.</para></listitem>
diff --git a/gmime/gmime-multipart-encrypted.c b/gmime/gmime-multipart-encrypted.c
index 5793654..f0a383a 100644
--- a/gmime/gmime-multipart-encrypted.c
+++ b/gmime/gmime-multipart-encrypted.c
@@ -129,7 +129,7 @@ g_mime_multipart_encrypted_new (void)
        multipart = g_object_newv (GMIME_TYPE_MULTIPART_ENCRYPTED, 0, NULL);
        
        content_type = g_mime_content_type_new ("multipart", "encrypted");
-       g_mime_object_set_content_type (GMIME_OBJECT (multipart), content_type);
+       g_mime_object_set_content_type ((GMimeObject *) multipart, content_type);
        g_object_unref (content_type);
        
        return multipart;
@@ -138,9 +138,8 @@ g_mime_multipart_encrypted_new (void)
 
 /**
  * g_mime_multipart_encrypted_encrypt:
- * @mpe: multipart/encrypted object
- * @content: MIME part to encrypt
- * @ctx: encryption context
+ * @ctx: a #GMimeCryptoContext
+ * @entity: MIME part to encrypt
  * @sign: %TRUE if the content should also be signed or %FALSE otherwise
  * @userid: user id to use for signing (only used if @sign is %TRUE)
  * @digest: digest algorithm to use when signing
@@ -148,49 +147,47 @@ g_mime_multipart_encrypted_new (void)
  * @recipients: (element-type utf8): an array of recipients to encrypt to
  * @err: a #GError
  *
- * Attempts to encrypt (and conditionally sign) the @content MIME part
+ * Attempts to encrypt (and conditionally sign) the @entity MIME part
  * to the public keys of @recipients using the @ctx encryption
- * context. If successful, the encrypted #GMimeObject is set as the
- * encrypted part of the multipart/encrypted object @mpe.
+ * context. If successful, a new multipart/encrypted object is returned.
  *
- * Returns: %0 on success or %-1 on fail. If the encryption fails, an
- * exception will be set on @err to provide information as to why the
- * failure occured.
+ * Returns: a new #GMimeMultipartEncrypted object on success or %NULL on fail.
+ * If encrypting fails, an exception will be set on @err to provide information
+ * as to why the failure occured.
  **/
-int
-g_mime_multipart_encrypted_encrypt (GMimeMultipartEncrypted *mpe, GMimeObject *content,
-                                   GMimeCryptoContext *ctx, gboolean sign, const char *userid,
-                                   GMimeDigestAlgo digest, GMimeEncryptFlags flags,
-                                   GPtrArray *recipients, GError **err)
+GMimeMultipartEncrypted *
+g_mime_multipart_encrypted_encrypt (GMimeCryptoContext *ctx, GMimeObject *entity,
+                                   gboolean sign, const char *userid, GMimeDigestAlgo digest,
+                                   GMimeEncryptFlags flags, GPtrArray *recipients, GError **err)
 {
        GMimeParserOptions *options = g_mime_parser_options_get_default ();
-       GMimeStream *filtered_stream, *ciphertext, *stream;
+       GMimeStream *filtered, *stream, *ciphertext;
        GMimePart *version_part, *encrypted_part;
+       GMimeMultipartEncrypted *encrypted;
        GMimeContentType *content_type;
-       GMimeDataWrapper *wrapper;
-       GMimeFilter *crlf_filter;
+       GMimeDataWrapper *content;
        const char *protocol;
+       GMimeFilter *filter;
        
-       g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED (mpe), -1);
-       g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), -1);
-       g_return_val_if_fail (GMIME_IS_OBJECT (content), -1);
+       g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), NULL);
+       g_return_val_if_fail (GMIME_IS_OBJECT (entity), NULL);
        
        if (!(protocol = g_mime_crypto_context_get_encryption_protocol (ctx))) {
                g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("Encryption not 
supported."));
-               return -1;
+               return NULL;
        }
        
        /* get the cleartext */
        stream = g_mime_stream_mem_new ();
-       filtered_stream = g_mime_stream_filter_new (stream);
+       filtered = g_mime_stream_filter_new (stream);
        
-       crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE);
-       g_mime_stream_filter_add (GMIME_STREAM_FILTER (filtered_stream), crlf_filter);
-       g_object_unref (crlf_filter);
+       filter = g_mime_filter_crlf_new (TRUE, FALSE);
+       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+       g_object_unref (filter);
        
-       g_mime_object_write_to_stream (content, filtered_stream);
-       g_mime_stream_flush (filtered_stream);
-       g_object_unref (filtered_stream);
+       g_mime_object_write_to_stream (entity, filtered);
+       g_mime_stream_flush (filtered);
+       g_object_unref (filtered);
        
        /* reset the content stream */
        g_mime_stream_reset (stream);
@@ -200,7 +197,7 @@ g_mime_multipart_encrypted_encrypt (GMimeMultipartEncrypted *mpe, GMimeObject *c
        if (g_mime_crypto_context_encrypt (ctx, sign, userid, digest, flags, recipients, stream, ciphertext, 
err) == -1) {
                g_object_unref (ciphertext);
                g_object_unref (stream);
-               return -1;
+               return NULL;
        }
        
        g_object_unref (stream);
@@ -212,47 +209,47 @@ g_mime_multipart_encrypted_encrypt (GMimeMultipartEncrypted *mpe, GMimeObject *c
        g_object_unref (content_type);
        
        content_type = g_mime_content_type_parse (options, protocol);
-       g_mime_object_set_content_type (GMIME_OBJECT (version_part), content_type);
+       g_mime_object_set_content_type ((GMimeObject *) version_part, content_type);
        g_mime_part_set_content_encoding (version_part, GMIME_CONTENT_ENCODING_7BIT);
        stream = g_mime_stream_mem_new_with_buffer ("Version: 1\n", strlen ("Version: 1\n"));
-       wrapper = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_7BIT);
-       g_mime_part_set_content (version_part, wrapper);
-       g_object_unref (wrapper);
+       content = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_7BIT);
+       g_mime_part_set_content (version_part, content);
+       g_object_unref (content);
        g_object_unref (stream);
        
        /* construct the encrypted mime part */
        encrypted_part = g_mime_part_new_with_type ("application", "octet-stream");
        g_mime_part_set_content_encoding (encrypted_part, GMIME_CONTENT_ENCODING_7BIT);
-       wrapper = g_mime_data_wrapper_new_with_stream (ciphertext, GMIME_CONTENT_ENCODING_7BIT);
-       g_mime_part_set_content (encrypted_part, wrapper);
+       content = g_mime_data_wrapper_new_with_stream (ciphertext, GMIME_CONTENT_ENCODING_7BIT);
+       g_mime_part_set_content (encrypted_part, content);
        g_object_unref (ciphertext);
-       g_object_unref (wrapper);
+       g_object_unref (content);
        
        /* save the version and encrypted parts */
-       /* FIXME: make sure there aren't any other parts?? */
-       g_mime_multipart_add (GMIME_MULTIPART (mpe), GMIME_OBJECT (version_part));
-       g_mime_multipart_add (GMIME_MULTIPART (mpe), GMIME_OBJECT (encrypted_part));
+       encrypted = g_mime_multipart_encrypted_new ();
+       g_mime_multipart_add ((GMimeMultipart *) encrypted, (GMimeObject *) version_part);
+       g_mime_multipart_add ((GMimeMultipart *) encrypted, (GMimeObject *) encrypted_part);
        g_object_unref (encrypted_part);
        g_object_unref (version_part);
        
        /* set the content-type params for this multipart/encrypted part */
-       g_mime_object_set_content_type_parameter (GMIME_OBJECT (mpe), "protocol", protocol);
-       g_mime_multipart_set_boundary (GMIME_MULTIPART (mpe), NULL);
+       g_mime_object_set_content_type_parameter ((GMimeObject *) encrypted, "protocol", protocol);
+       g_mime_multipart_set_boundary ((GMimeMultipart *) encrypted, NULL);
        
-       return 0;
+       return encrypted;
 }
 
 
 /**
  * g_mime_multipart_encrypted_decrypt:
- * @mpe: multipart/encrypted object
+ * @encrypted: a #GMimeMultipartEncrypted
  * @flags: a #GMimeDecryptFlags
  * @session_key: session key to use or %NULL
  * @result: a #GMimeDecryptionResult
  * @err: a #GError
  *
  * Attempts to decrypt the encrypted MIME part contained within the
- * multipart/encrypted object @mpe.
+ * multipart/encrypted object @encrypted.
  *
  * When non-%NULL, @session_key should be a %NULL-terminated string,
  * such as the one returned by g_mime_decrypt_result_get_session_key()
@@ -269,28 +266,27 @@ g_mime_multipart_encrypted_encrypt (GMimeMultipartEncrypted *mpe, GMimeObject *c
  * @err to provide information as to why the failure occured.
  **/
 GMimeObject *
-g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe, GMimeDecryptFlags flags,
+g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *encrypted, GMimeDecryptFlags flags,
                                    const char *session_key, GMimeDecryptResult **result,
                                    GError **err)
 {
-       GMimeObject *decrypted, *version, *encrypted;
-       GMimeStream *stream, *ciphertext;
+       GMimeObject *decrypted, *version_part, *encrypted_part;
+       GMimeStream *filtered, *stream, *ciphertext;
        const char *protocol, *supported;
-       GMimeStream *filtered_stream;
        GMimeContentType *mime_type;
        GMimeDataWrapper *content;
-       GMimeFilter *crlf_filter;
        GMimeDecryptResult *res;
        GMimeCryptoContext *ctx;
+       GMimeFilter *filter;
        GMimeParser *parser;
        char *content_type;
        
-       g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED (mpe), NULL);
+       g_return_val_if_fail (GMIME_IS_MULTIPART_ENCRYPTED (encrypted), NULL);
        
        if (result)
                *result = NULL;
        
-       if (!(protocol = g_mime_object_get_content_type_parameter (GMIME_OBJECT (mpe), "protocol"))) {
+       if (!(protocol = g_mime_object_get_content_type_parameter ((GMimeObject *) encrypted, "protocol"))) {
                g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PROTOCOL_ERROR,
                                     _("Cannot decrypt multipart/encrypted part: unspecified encryption 
protocol."));
                
@@ -317,10 +313,10 @@ g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe, GMimeDecryptFl
                return NULL;
        }
        
-       version = g_mime_multipart_get_part (GMIME_MULTIPART (mpe), GMIME_MULTIPART_ENCRYPTED_VERSION);
+       version_part = g_mime_multipart_get_part ((GMimeMultipart *) encrypted, 
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);
+       content_type = g_mime_content_type_to_string (version_part->content_type);
        if (g_ascii_strcasecmp (content_type, protocol) != 0) {
                g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
                                     _("Cannot decrypt multipart/encrypted part: content-type does not match 
protocol."));
@@ -333,8 +329,8 @@ g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe, GMimeDecryptFl
        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);
+       encrypted_part = g_mime_multipart_get_part ((GMimeMultipart *) encrypted, 
GMIME_MULTIPART_ENCRYPTED_CONTENT);
+       mime_type = g_mime_object_get_content_type (encrypted_part);
        if (!g_mime_content_type_is_type (mime_type, "application", "octet-stream")) {
                g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_PARSE_ERROR,
                                     _("Cannot decrypt multipart/encrypted part: unexpected content type."));
@@ -344,30 +340,30 @@ g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe, GMimeDecryptFl
        }
        
        /* get the ciphertext stream */
-       content = g_mime_part_get_content (GMIME_PART (encrypted));
+       content = g_mime_part_get_content ((GMimePart *) encrypted_part);
        ciphertext = g_mime_stream_mem_new ();
        g_mime_data_wrapper_write_to_stream (content, ciphertext);
        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);
+       filtered = g_mime_stream_filter_new (stream);
+       filter = g_mime_filter_crlf_new (FALSE, FALSE);
+       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+       g_object_unref (filter);
        
        /* get the cleartext */
-       if (!(res = g_mime_crypto_context_decrypt (ctx, flags, session_key, ciphertext, filtered_stream, 
err))) {
-               g_object_unref (filtered_stream);
+       if (!(res = g_mime_crypto_context_decrypt (ctx, flags, session_key, ciphertext, filtered, err))) {
                g_object_unref (ciphertext);
+               g_object_unref (filtered);
                g_object_unref (stream);
                g_object_unref (ctx);
                
                return NULL;
        }
        
-       g_mime_stream_flush (filtered_stream);
-       g_object_unref (filtered_stream);
+       g_mime_stream_flush (filtered);
        g_object_unref (ciphertext);
+       g_object_unref (filtered);
        g_object_unref (ctx);
        
        g_mime_stream_reset (stream);
diff --git a/gmime/gmime-multipart-encrypted.h b/gmime/gmime-multipart-encrypted.h
index 8f6c771..6567aef 100644
--- a/gmime/gmime-multipart-encrypted.h
+++ b/gmime/gmime-multipart-encrypted.h
@@ -64,13 +64,11 @@ GType g_mime_multipart_encrypted_get_type (void);
 
 GMimeMultipartEncrypted *g_mime_multipart_encrypted_new (void);
 
-int g_mime_multipart_encrypted_encrypt (GMimeMultipartEncrypted *mpe, GMimeObject *content,
-                                       GMimeCryptoContext *ctx, gboolean sign,
-                                       const char *userid, GMimeDigestAlgo digest,
-                                       GMimeEncryptFlags flags, GPtrArray *recipients,
-                                       GError **err);
+GMimeMultipartEncrypted *g_mime_multipart_encrypted_encrypt (GMimeCryptoContext *ctx, GMimeObject *entity,
+                                                            gboolean sign, const char *user_id, 
GMimeDigestAlgo digest,
+                                                            GMimeEncryptFlags flags, GPtrArray *recipients, 
GError **err);
 
-GMimeObject *g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *mpe,
+GMimeObject *g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *encrypted,
                                                 GMimeDecryptFlags flags,
                                                 const char *session_key,
                                                 GMimeDecryptResult **result,
diff --git a/gmime/gmime-multipart-signed.c b/gmime/gmime-multipart-signed.c
index 0632c9a..c12c601 100644
--- a/gmime/gmime-multipart-signed.c
+++ b/gmime/gmime-multipart-signed.c
@@ -143,7 +143,7 @@ g_mime_multipart_signed_new (void)
        multipart = g_object_newv (GMIME_TYPE_MULTIPART_SIGNED, 0, NULL);
        
        content_type = g_mime_content_type_new ("multipart", "signed");
-       g_mime_object_set_content_type (GMIME_OBJECT (multipart), content_type);
+       g_mime_object_set_content_type ((GMimeObject *) multipart, content_type);
        g_object_unref (content_type);
        
        return multipart;
@@ -184,60 +184,57 @@ sign_prepare (GMimeObject *mime_part)
                subpart = GMIME_MESSAGE_PART (mime_part)->message->mime_part;
                sign_prepare (subpart);
        } else {
-               encoding = g_mime_part_get_content_encoding (GMIME_PART (mime_part));
+               encoding = g_mime_part_get_content_encoding ((GMimePart *) mime_part);
                
                if (encoding != GMIME_CONTENT_ENCODING_BASE64)
-                       g_mime_part_set_content_encoding (GMIME_PART (mime_part),
-                                                         GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
+                       g_mime_part_set_content_encoding ((GMimePart *) mime_part, 
GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE);
        }
 }
 
 
 /**
  * g_mime_multipart_signed_sign:
- * @mps: multipart/signed object
- * @content: MIME part to sign
- * @ctx: encryption crypto context
+ * @ctx: a #GMimeCryptoContext
+ * @entity: MIME part to sign
  * @userid: user id to sign with
  * @digest: preferred digest algorithm
- * @err: exception
+ * @err: a #GError
  *
  * Attempts to sign the @content MIME part with @userid's private key
  * using the @ctx signing context with the @digest algorithm. If
- * successful, the signed #GMimeObject is set as the signed part of
- * the multipart/signed object @mps.
+ * successful, a new multipart/signed object is returned.
  *
- * Returns: %0 on success or %-1 on fail. If the signing fails, an
- * exception will be set on @err to provide information as to why the
- * failure occured.
+ * Returns: a new #GMimeMultipartSigned object on success or %NULL on fail.
+ * If signing fails, an exception will be set on @err to provide information
+ * as to why the failure occured.
  **/
-int
-g_mime_multipart_signed_sign (GMimeMultipartSigned *mps, GMimeObject *content,
-                             GMimeCryptoContext *ctx, const char *userid,
-                             GMimeDigestAlgo digest, GError **err)
+GMimeMultipartSigned *
+g_mime_multipart_signed_sign (GMimeCryptoContext *ctx, GMimeObject *entity,
+                             const char *userid, GMimeDigestAlgo digest,
+                             GError **err)
 {
        GMimeParserOptions *options = g_mime_parser_options_get_default ();
        GMimeStream *stream, *filtered, *sigstream;
        GMimeContentType *content_type;
-       GMimeDataWrapper *wrapper;
+       GMimeDataWrapper *content;
+       GMimeMultipartSigned *mps;
        GMimePart *signature;
        GMimeFilter *filter;
        GMimeParser *parser;
        const char *protocol;
        const char *micalg;
-       int rv;
+       int algo;
        
-       g_return_val_if_fail (GMIME_IS_MULTIPART_SIGNED (mps), -1);
-       g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), -1);
-       g_return_val_if_fail (GMIME_IS_OBJECT (content), -1);
+       g_return_val_if_fail (GMIME_IS_CRYPTO_CONTEXT (ctx), NULL);
+       g_return_val_if_fail (GMIME_IS_OBJECT (entity), NULL);
        
        if (!(protocol = g_mime_crypto_context_get_signature_protocol (ctx))) {
                g_set_error_literal (err, GMIME_ERROR, GMIME_ERROR_NOT_SUPPORTED, _("Signing not 
supported."));
-               return -1;
+               return NULL;
        }
        
        /* Prepare all the parts for signing... */
-       sign_prepare (content);
+       sign_prepare (entity);
        
        /* get the cleartext */
        stream = g_mime_stream_mem_new ();
@@ -245,34 +242,34 @@ g_mime_multipart_signed_sign (GMimeMultipartSigned *mps, GMimeObject *content,
        
        /* 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_mime_stream_filter_add ((GMimeStreamFilter *) 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_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
-       g_mime_object_write_to_stream (content, filtered);
+       g_mime_object_write_to_stream (entity, filtered);
        g_mime_stream_flush (filtered);
-       g_object_unref (filtered);
        g_mime_stream_reset (stream);
+       g_object_unref (filtered);
        
        /* 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_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
        /* construct the signature stream */
        sigstream = g_mime_stream_mem_new ();
        
        /* sign the content stream */
-       if ((rv = g_mime_crypto_context_sign (ctx, TRUE, userid, digest, filtered, sigstream, err)) == -1) {
+       if ((algo = g_mime_crypto_context_sign (ctx, TRUE, userid, digest, filtered, sigstream, err)) == -1) {
                g_object_unref (sigstream);
                g_object_unref (filtered);
                g_object_unref (stream);
-               return -1;
+               return NULL;
        }
        
        g_object_unref (filtered);
@@ -280,15 +277,15 @@ g_mime_multipart_signed_sign (GMimeMultipartSigned *mps, GMimeObject *content,
        g_mime_stream_reset (stream);
        
        /* set the multipart/signed protocol and micalg */
-       content_type = g_mime_object_get_content_type (GMIME_OBJECT (mps));
+       content_type = g_mime_object_get_content_type ((GMimeObject *) mps);
        g_mime_content_type_set_parameter (content_type, "protocol", protocol);
-       micalg = g_strdup (g_mime_crypto_context_digest_name (ctx, (GMimeDigestAlgo) rv));
+       micalg = g_strdup (g_mime_crypto_context_digest_name (ctx, (GMimeDigestAlgo) algo));
        g_mime_content_type_set_parameter (content_type, "micalg", micalg);
-       g_mime_multipart_set_boundary (GMIME_MULTIPART (mps), NULL);
+       g_mime_multipart_set_boundary ((GMimeMultipart *) mps, NULL);
        
        /* construct the content part */
        parser = g_mime_parser_new_with_stream (stream);
-       content = g_mime_parser_construct_part (parser);
+       entity = g_mime_parser_construct_part (parser);
        g_object_unref (stream);
        g_object_unref (parser);
        
@@ -297,11 +294,11 @@ g_mime_multipart_signed_sign (GMimeMultipartSigned *mps, GMimeObject *content,
        signature = g_mime_part_new_with_type (content_type->type, content_type->subtype);
        g_object_unref (content_type);
        
-       wrapper = g_mime_data_wrapper_new ();
-       g_mime_data_wrapper_set_stream (wrapper, sigstream);
-       g_mime_part_set_content (signature, wrapper);
+       content = g_mime_data_wrapper_new ();
+       g_mime_data_wrapper_set_stream (content, sigstream);
+       g_mime_part_set_content (signature, content);
        g_object_unref (sigstream);
-       g_object_unref (wrapper);
+       g_object_unref (content);
        
        /* FIXME: temporary hack, this info should probably be set in
         * the CryptoContext class - maybe ::sign can take/output a
@@ -312,13 +309,13 @@ g_mime_multipart_signed_sign (GMimeMultipartSigned *mps, GMimeObject *content,
        }
        
        /* 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);
+       mps = g_mime_multipart_signed_new ();
+       g_mime_multipart_add ((GMimeMultipart *) mps, entity);
+       g_mime_multipart_add ((GMimeMultipart *) mps, (GMimeObject *) signature);
        g_object_unref (signature);
-       g_object_unref (content);
+       g_object_unref (entity);
        
-       return 0;
+       return mps;
 }
 
 static gboolean
@@ -358,9 +355,9 @@ check_protocol_supported (const char *protocol, const char *supported)
 
 /**
  * g_mime_multipart_signed_verify:
- * @mps: multipart/signed object
+ * @mps: a #GMimeMultipartSigned
  * @flags: a #GMimeVerifyFlags
- * @err: exception
+ * @err: a #GError
  *
  * Attempts to verify the signed MIME part contained within the
  * multipart/signed object @mps.
diff --git a/gmime/gmime-multipart-signed.h b/gmime/gmime-multipart-signed.h
index b61c75a..b82f3d1 100644
--- a/gmime/gmime-multipart-signed.h
+++ b/gmime/gmime-multipart-signed.h
@@ -64,9 +64,9 @@ GType g_mime_multipart_signed_get_type (void);
 
 GMimeMultipartSigned *g_mime_multipart_signed_new (void);
 
-int g_mime_multipart_signed_sign (GMimeMultipartSigned *mps, GMimeObject *content,
-                                 GMimeCryptoContext *ctx, const char *userid,
-                                 GMimeDigestAlgo digest, GError **err);
+GMimeMultipartSigned *g_mime_multipart_signed_sign (GMimeCryptoContext *ctx, GMimeObject *entity,
+                                                   const char *userid, GMimeDigestAlgo digest,
+                                                   GError **err);
 
 GMimeSignatureList *g_mime_multipart_signed_verify (GMimeMultipartSigned *mps, GMimeVerifyFlags flags, 
GError **err);
 
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index f31a9b9..9b0cebc 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -160,44 +160,14 @@ print_verify_results (GMimeSignatureList *signatures)
        }
 }
 
-#define MULTIPART_SIGNED_CONTENT "This is a test of the emergency broadcast system \
-with an sha1 detach-sign.\n\nFrom now on, there will be text to try and break     \t\
-  \nvarious things. For example, the F in \"From\" in the previous line...\n...and \
-the first dot of this line have been pre-encoded in the QP encoding in order to test \
-that GMime properly treats MIME part content as opaque.\nIf this still verifies okay, \
-then we have ourselves a winner I guess...\n"
-
-static void
-test_multipart_signed (GMimeCryptoContext *ctx)
+static GMimeMessage *
+create_message (GMimeObject *body)
 {
-       GMimeSignatureList *signatures;
-       GMimeMultipartSigned *mps;
        InternetAddressList *list;
        InternetAddress *mailbox;
        GMimeMessage *message;
-       GMimeStream *stream;
        GMimeParser *parser;
-       GMimeTextPart *part;
-       GError *err = NULL;
-       Exception *ex;
-       
-       part = g_mime_text_part_new_with_subtype ("plain");
-       g_mime_text_part_set_text (part, MULTIPART_SIGNED_CONTENT);
-       
-       /* create the multipart/signed container part */
-       mps = g_mime_multipart_signed_new ();
-       
-       /* sign the part */
-       g_mime_multipart_signed_sign (mps, GMIME_OBJECT (part), ctx, "no.user@no.domain",
-                                     GMIME_DIGEST_ALGO_SHA1, &err);
-       g_object_unref (part);
-       
-       if (err != NULL) {
-               ex = exception_new ("signing failed: %s", err->message);
-               g_object_unref (mps);
-               g_error_free (err);
-               throw (ex);
-       }
+       GMimeStream *stream;
        
        message = g_mime_message_new (TRUE);
        
@@ -218,14 +188,17 @@ test_multipart_signed (GMimeCryptoContext *ctx)
        
        g_mime_message_set_subject (message, "This is a test message", NULL);
        g_mime_object_set_header ((GMimeObject *) message, "X-Mailer", "main.c");
-       g_mime_message_set_mime_part (message, GMIME_OBJECT (mps));
-       g_object_unref (mps);
+       g_mime_message_set_mime_part (message, body);
        
        stream = g_mime_stream_mem_new ();
        g_mime_object_write_to_stream ((GMimeObject *) message, stream);
        g_mime_stream_reset (stream);
        g_object_unref (message);
        
+       /*fprintf (stderr, "-----BEGIN RAW MESSAGE-----\n%.*s-----END RAW MESSAGE-----\n",
+                GMIME_STREAM_MEM (stream)->buffer->len,
+                GMIME_STREAM_MEM (stream)->buffer->data);*/
+       
        parser = g_mime_parser_new ();
        g_mime_parser_init_with_stream (parser, stream);
        g_object_unref (stream);
@@ -233,6 +206,43 @@ test_multipart_signed (GMimeCryptoContext *ctx)
        message = g_mime_parser_construct_message (parser);
        g_object_unref (parser);
        
+       return message;
+}
+
+#define MULTIPART_SIGNED_CONTENT "This is a test of the emergency broadcast system \
+with an sha1 detach-sign.\n\nFrom now on, there will be text to try and break     \t\
+  \nvarious things. For example, the F in \"From\" in the previous line...\n...and \
+the first dot of this line have been pre-encoded in the QP encoding in order to test \
+that GMime properly treats MIME part content as opaque.\nIf this still verifies okay, \
+then we have ourselves a winner I guess...\n"
+
+static void
+test_multipart_signed (GMimeCryptoContext *ctx)
+{
+       GMimeSignatureList *signatures;
+       GMimeMultipartSigned *mps;
+       GMimeMessage *message;
+       GMimeTextPart *part;
+       GError *err = NULL;
+       Exception *ex;
+       
+       part = g_mime_text_part_new_with_subtype ("plain");
+       g_mime_text_part_set_text (part, MULTIPART_SIGNED_CONTENT);
+       
+       /* sign the part */
+       mps = g_mime_multipart_signed_sign (ctx, (GMimeObject *) part, "no.user@no.domain",
+                                           GMIME_DIGEST_ALGO_SHA1, &err);
+       g_object_unref (part);
+       
+       if (err != NULL) {
+               ex = exception_new ("signing failed: %s", err->message);
+               g_error_free (err);
+               throw (ex);
+       }
+       
+       message = create_message ((GMimeObject *) mps);
+       g_object_unref (mps);
+       
        if (!GMIME_IS_MULTIPART_SIGNED (message->mime_part)) {
                ex = exception_new ("resultant top-level mime part not a multipart/signed?");
                g_object_unref (message);
@@ -278,22 +288,18 @@ create_encrypted_message (GMimeCryptoContext *ctx, gboolean sign,
        g_mime_object_write_to_stream ((GMimeObject *) part, cleartext);
        g_mime_stream_reset (cleartext);
        
-       /* create the multipart/encrypted container part */
-       mpe = g_mime_multipart_encrypted_new ();
-       
        /* encrypt the part */
        recipients = g_ptr_array_new ();
        g_ptr_array_add (recipients, "no.user@no.domain");
-       g_mime_multipart_encrypted_encrypt (mpe, GMIME_OBJECT (part), ctx, sign,
-                                           "no.user@no.domain", GMIME_DIGEST_ALGO_SHA256,
-                                           GMIME_ENCRYPT_FLAGS_ALWAYS_TRUST, recipients, &err);
+       mpe = g_mime_multipart_encrypted_encrypt (ctx, (GMimeObject *) part,
+                                                 sign, "no.user@no.domain", GMIME_DIGEST_ALGO_SHA256,
+                                                 GMIME_ENCRYPT_FLAGS_ALWAYS_TRUST, recipients, &err);
        g_ptr_array_free (recipients, TRUE);
        g_object_unref (part);
        
        if (err != NULL) {
                ex = exception_new ("encryption failed: %s", err->message);
                g_object_unref (cleartext);
-               g_object_unref (mpe);
                g_error_free (err);
                throw (ex);
        }
diff --git a/tests/test-smime.c b/tests/test-smime.c
index f842601..c3f7dc0 100644
--- a/tests/test-smime.c
+++ b/tests/test-smime.c
@@ -231,17 +231,13 @@ test_multipart_signed (GMimeCryptoContext *ctx)
        part = g_mime_text_part_new_with_subtype ("plain");
        g_mime_text_part_set_text (part, MULTIPART_SIGNED_CONTENT);
        
-       /* create the multipart/signed container part */
-       mps = g_mime_multipart_signed_new ();
-       
        /* sign the part */
-       g_mime_multipart_signed_sign (mps, GMIME_OBJECT (part), ctx, "mimekit example com",
-                                     GMIME_DIGEST_ALGO_SHA1, &err);
+       mps = g_mime_multipart_signed_sign (ctx, (GMimeObject *) part, "mimekit example com",
+                                           GMIME_DIGEST_ALGO_SHA1, &err);
        g_object_unref (part);
        
        if (err != NULL) {
                ex = exception_new ("signing failed: %s", err->message);
-               g_object_unref (mps);
                g_error_free (err);
                throw (ex);
        }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]