Re: [evolution-patches] Mailer bug #127521: Inline PGP support for evolution (part A: only sending)
- From: Jeffrey Stedfast <fejj ximian com>
- To: Bohumir Jelinek <bj48 ra msstate edu>
- Cc: evolution-patches ximian com
- Subject: Re: [evolution-patches] Mailer bug #127521: Inline PGP support for evolution (part A: only sending)
- Date: Tue, 06 Jan 2004 11:07:34 -0500
comments below...
On Tue, 2004-01-06 at 06:48 -0600, Bohumir Jelinek wrote:
> This is unencoded version of the patch.
>
> -Bohumir
>
> Index: camel/ChangeLog
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/ChangeLog,v
> retrieving revision 1.1922
> diff -u -r1.1922 ChangeLog
> --- camel/ChangeLog 26 Nov 2003 19:32:15 -0000 1.1922
> +++ camel/ChangeLog 6 Jan 2004 12:07:05 -0000
> @@ -1,3 +1,12 @@
> +2004-01-06 Bohumir Jelinek <bj48 msstate edu>
> +
> + * camel-cipher-context.c (cipher_clearsign): signs plain text
> + (camel_cipher_dw_to_canon_stream): filters plain text
> + * camel-cipher-context.h: added prototypes for above
> + * camel-gpg-context.c: added GPG_CTX_MODE_CLEARSIGN enumeration
> + (gpg_clearsign): signs plain text
> + * e-msg-composer.c (build_message): modified to offer clearsign
> +
> 2003-11-26 JP Rosevear <jpr ximian com>
>
> * Makefile.am: make sure we always dist the smime stuff
> Index: camel/camel-cipher-context.c
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/camel-cipher-context.c,v
> retrieving revision 1.16
> diff -u -r1.16 camel-cipher-context.c
> --- camel/camel-cipher-context.c 24 Nov 2003 22:38:12 -0000 1.16
> +++ camel/camel-cipher-context.c 6 Jan 2004 12:07:05 -0000
> @@ -102,6 +102,15 @@
> return -1;
> }
>
> +static int
> +cipher_clearsign (CamelCipherContext *ctx, const char *userid, CamelCipherHash hash,
> + struct _CamelDataWrapper *plain, struct _CamelDataWrapper *current, CamelException *ex)
> +{
> + camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
> + _("Inline signing is not supported by this cipher"));
> + return -1;
> +}
> +
> /**
> * camel_cipher_sign:
> * @context: Cipher Context
> @@ -133,6 +142,35 @@
> return retval;
> }
>
> +/**
> + * camel_cipher_clearsign:
> + * @context: Cipher Context
> + * @userid: private key to use to sign the stream
> + * @hash: preferred Message-Integrity-Check hash algorithm
> + * @iopart: Input/output part.
> + * @ex: exception
> + *
> + * Appends signature at the end of plain text part @iopart.
> + *
> + * Return value: 0 for success or -1 for failure.
> + **/
> +int
> +camel_cipher_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
> + struct _CamelDataWrapper *plain, struct _CamelDataWrapper *current, CamelException *ex)
> +{
> + int retval;
> +
> + g_return_val_if_fail (CAMEL_IS_CIPHER_CONTEXT (context), -1);
> +
> + CIPHER_LOCK(context);
> +
> + retval = CCC_CLASS (context)->clearsign (context, userid, hash, plain, current, ex);
> +
> + CIPHER_UNLOCK(context);
> +
> + return retval;
> +}
> +
> static CamelCipherValidity *
> cipher_verify (CamelCipherContext *context, struct _CamelMimePart *sigpart, CamelException *ex)
> {
> @@ -490,6 +528,7 @@
> camel_cipher_context_class->hash_to_id = cipher_hash_to_id;
> camel_cipher_context_class->id_to_hash = cipher_id_to_hash;
> camel_cipher_context_class->sign = cipher_sign;
> + camel_cipher_context_class->clearsign = cipher_clearsign;
> camel_cipher_context_class->verify = cipher_verify;
> camel_cipher_context_class->encrypt = cipher_encrypt;
> camel_cipher_context_class->decrypt = cipher_decrypt;
> @@ -583,3 +622,37 @@
>
> return res;
> }
> +
> +/**
> + * camel_cipher_dw_to_canon_stream:
> + * @dw: data wrapper to write.
> + * @flags: flags for the canonicalisation filter (CamelMimeFilterCanon)
> + * @ostream: stream to write canonicalised output to.
> + *
> + * Writes a dw to a stream in a canonicalised format, suitable for signing/encrypting.
> + *
> + * Return value: -1 on error;
> + **/
> +int
> +camel_cipher_dw_to_canon_stream(CamelDataWrapper *dw, guint32 flags, CamelStream *ostream)
> +{
this function should be renamed to:
camel_cipher_data_wrapper_to_canon_stream()
> + CamelStreamFilter *filter;
> + CamelMimeFilter *canon;
> + int res = -1;
> +
> + filter = camel_stream_filter_new_with_stream(ostream);
> +
> + canon = camel_mime_filter_canon_new(flags);
> + camel_stream_filter_add(filter, canon);
> + camel_object_unref(canon);
> +
> + if (camel_data_wrapper_write_to_stream(dw, (CamelStream *)filter) != -1
> + && camel_stream_flush((CamelStream *)filter) != -1)
> + res = 0;
> +
> + camel_object_unref(filter);
> +
> + camel_stream_reset(ostream);
> +
> + return res;
> +}
> Index: camel/camel-cipher-context.h
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/camel-cipher-context.h,v
> retrieving revision 1.14
> diff -u -r1.14 camel-cipher-context.h
> --- camel/camel-cipher-context.h 24 Nov 2003 22:38:12 -0000 1.14
> +++ camel/camel-cipher-context.h 6 Jan 2004 12:07:06 -0000
> @@ -105,6 +105,9 @@
> int (*sign) (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
> struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex);
>
> + int (*clearsign) (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
> + struct _CamelDataWrapper *plain, struct _CamelDataWrapper *current, CamelException *ex);
> +
> CamelCipherValidity * (*verify) (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
>
> int (*encrypt) (CamelCipherContext *context, const char *userid,
> @@ -139,6 +142,8 @@
> /* cipher routines */
> int camel_cipher_sign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
> struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex);
> +int camel_cipher_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash,
> + struct _CamelDataWrapper *plain, struct _CamelDataWrapper *current, CamelException *ex);
> CamelCipherValidity *camel_cipher_verify (CamelCipherContext *context, struct _CamelMimePart *ipart, CamelException *ex);
> int camel_cipher_encrypt (CamelCipherContext *context, const char *userid,
> GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart,
> @@ -166,6 +171,7 @@
>
> /* utility functions */
> int camel_cipher_canonical_to_stream(CamelMimePart *part, guint32 flags, CamelStream *ostream);
> +int camel_cipher_dw_to_canon_stream(CamelDataWrapper *dw, guint32 flags, CamelStream *ostream);
>
> #ifdef __cplusplus
> }
> Index: camel/camel-gpg-context.c
> ===================================================================
> RCS file: /cvs/gnome/evolution/camel/camel-gpg-context.c,v
> retrieving revision 1.40
> diff -u -r1.40 camel-gpg-context.c
> --- camel/camel-gpg-context.c 13 Nov 2003 23:17:30 -0000 1.40
> +++ camel/camel-gpg-context.c 6 Jan 2004 12:07:06 -0000
> @@ -148,6 +148,7 @@
>
> enum _GpgCtxMode {
> GPG_CTX_MODE_SIGN,
> + GPG_CTX_MODE_CLEARSIGN,
> GPG_CTX_MODE_VERIFY,
> GPG_CTX_MODE_ENCRYPT,
> GPG_CTX_MODE_DECRYPT,
> @@ -294,7 +295,7 @@
> gpg_ctx_set_mode (struct _GpgCtx *gpg, enum _GpgCtxMode mode)
> {
> gpg->mode = mode;
> - gpg->need_passwd = ((gpg->mode == GPG_CTX_MODE_SIGN) || (gpg->mode == GPG_CTX_MODE_DECRYPT));
> + gpg->need_passwd = ((gpg->mode == GPG_CTX_MODE_SIGN) || (gpg->mode == GPG_CTX_MODE_DECRYPT) || (gpg->mode == GPG_CTX_MODE_CLEARSIGN));
> }
>
> static void
> @@ -494,6 +495,18 @@
> g_ptr_array_add (argv, "--output");
> g_ptr_array_add (argv, "-");
> break;
> + case GPG_CTX_MODE_CLEARSIGN:
> + g_ptr_array_add (argv, "--clearsign");
> + hash_str = gpg_hash_str (gpg->hash);
> + if (hash_str)
> + g_ptr_array_add (argv, (char *) hash_str);
> + if (gpg->userid) {
> + g_ptr_array_add (argv, "-u");
> + g_ptr_array_add (argv, (char *) gpg->userid);
> + }
> + g_ptr_array_add (argv, "--output");
> + g_ptr_array_add (argv, "-");
> + break;
> case GPG_CTX_MODE_VERIFY:
> if (!camel_session_is_online (gpg->session)) {
> /* this is a deprecated flag to gpg since 1.0.7 */
> @@ -806,6 +819,11 @@
> /* FIXME: save this state? */
> }
> break;
> + case GPG_CTX_MODE_CLEARSIGN:
> + if (!strncmp (status, "SIG_CREATED ", 12)) {
> + /* FIXME: save this state? */
> + }
> + break;
> case GPG_CTX_MODE_VERIFY:
> if (!strncmp (status, "TRUST_", 6)) {
> status += 6;
> @@ -1087,6 +1105,9 @@
> case GPG_CTX_MODE_SIGN:
> mode = "sign";
> break;
> + case GPG_CTX_MODE_CLEARSIGN:
> + mode = "clearsign";
> + break;
> case GPG_CTX_MODE_VERIFY:
> mode = "verify";
> break;
> @@ -1310,6 +1331,81 @@
> }
>
>
> +static int
> +gpg_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelDataWrapper *plain, CamelDataWrapper *current, CamelException *ex)
> +{
> + struct _GpgCtx *gpg;
> + CamelStream *ostream = camel_stream_mem_new(), *istream;
I'd prefer that you not init the ostream here.
> + CamelContentType *ct;
> + int res = -1;
> +
> + /* Note: see rfc2015 or rfc3156, section 5 */
those rfcs have nothing to do with clearsigning
> +
> + /* FIXME: stream this, we stream output at least */
> + istream = camel_stream_mem_new();
> + if (camel_cipher_dw_to_canon_stream(plain, CAMEL_MIME_FILTER_CANON_STRIP|CAMEL_MIME_FILTER_CANON_CRLF|CAMEL_MIME_FILTER_CANON_FROM,
> + istream) == -1) {
> + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
> + _("Could not generate signing data: %s"), g_strerror(errno));
> + goto fail;
> + }
> +
> + gpg = gpg_ctx_new (context->session);
> + gpg_ctx_set_mode (gpg, GPG_CTX_MODE_CLEARSIGN);
> + gpg_ctx_set_hash (gpg, hash);
> + gpg_ctx_set_userid (gpg, userid);
> + gpg_ctx_set_istream (gpg, istream);
> + gpg_ctx_set_ostream (gpg, ostream);
> +
> + if (gpg_ctx_op_start (gpg) == -1) {
> + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
> + _("Failed to execute gpg: %s"), g_strerror (errno));
> + goto fail;
> + }
> +
> + while (!gpg_ctx_op_complete (gpg)) {
> + if (camel_operation_cancel_check (NULL)) {
> + camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
> + _("Cancelled."));
> + gpg_ctx_op_cancel (gpg);
> + goto fail;
> + }
> +
> + if (gpg_ctx_op_step (gpg, ex) == -1) {
> + gpg_ctx_op_cancel (gpg);
> + goto fail;
> + }
> + }
> +
> + if (gpg_ctx_op_wait (gpg) != 0) {
> + const char *diagnostics;
> +
> + diagnostics = gpg_ctx_get_diagnostics (gpg);
> + camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
> + diagnostics && *diagnostics ? diagnostics :
> + _("Failed to execute gpg."));
> + goto fail;
> + }
> +
> + res = 0;
> +
> + camel_stream_reset(ostream);
> + camel_data_wrapper_construct_from_stream(current, ostream);
> +
> + ct = camel_content_type_new("application", "pgp");
> + camel_content_type_set_param(ct, "x-action", "sign");
> + camel_content_type_set_param(ct, "format", "text");
> + camel_data_wrapper_set_mime_type_field(current, ct);
> + camel_content_type_unref(ct);
add a space between the function name and the open '(' (same goes for
the rest of the code)
> +
> +fail:
> + camel_object_unref(ostream);
> + gpg_ctx_free (gpg);
> +
> + return res;
> +}
> +
> +
> static char *
> swrite (CamelMimePart *sigpart)
> {
> @@ -1740,6 +1836,7 @@
> cipher_class->hash_to_id = gpg_hash_to_id;
> cipher_class->id_to_hash = gpg_id_to_hash;
> cipher_class->sign = gpg_sign;
> + cipher_class->clearsign = gpg_clearsign;
> cipher_class->verify = gpg_verify;
> cipher_class->encrypt = gpg_encrypt;
> cipher_class->decrypt = gpg_decrypt;
> Index: composer/e-msg-composer.c
> ===================================================================
> RCS file: /cvs/gnome/evolution/composer/e-msg-composer.c,v
> retrieving revision 1.424
> diff -u -r1.424 e-msg-composer.c
> --- composer/e-msg-composer.c 26 Nov 2003 21:51:40 -0000 1.424
> +++ composer/e-msg-composer.c 6 Jan 2004 12:07:06 -0000
> @@ -370,6 +370,7 @@
> CamelException ex;
> GByteArray *data;
> int i;
> + gboolean clearsign = FALSE;
>
> if (composer->persist_stream_interface == CORBA_OBJECT_NIL)
> return NULL;
> @@ -575,11 +576,8 @@
> CamelInternetAddress *from = NULL;
> CamelCipherContext *cipher;
>
> - part = camel_mime_part_new ();
> - camel_medium_set_content_object (CAMEL_MEDIUM (part), current);
> if (current == plain)
> camel_mime_part_set_encoding (part, plain_encoding);
> - camel_object_unref (current);
>
> if (hdrs->account && hdrs->account->pgp_key && *hdrs->account->pgp_key) {
> pgp_userid = hdrs->account->pgp_key;
> @@ -589,19 +587,44 @@
> }
>
> if (composer->pgp_sign) {
> - CamelMimePart *npart = camel_mime_part_new();
> +
> + if (current == plain) {
> + /*
> + * For plain text message, ask user if he wants to use "clearsign"
> + */
> + clearsign = em_utils_prompt_user ((GtkWindow *) composer, GTK_RESPONSE_YES, NULL,
> + _("PGP signature of plain text message can be inlined.\nInline?"));
> + }
no no no... I'd prefer you add a menu item to specifically clearsign.
however, this option to clearsign should cause a prompt if the message
being signed is anything other than a single text/plain part
"You cannot clearsign a multipart message. Do you wish to use the PGP/
MIME specification to sign this message instead? Yes/No"
(wording might need improvement, but you get the idea)
if the user chooses "Yes", then promote the action to the PGP/MIME
signing, otherwise if the user selects "No", you should simply not
(clear)sign at all. Perhaps that should also be explained in the
prompt... not sure.
Jeff
--
Jeffrey Stedfast
Evolution Hacker - Ximian, Inc.
fejj ximian com - www.ximian.com
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]