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);
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}