Re: [evolution-patches] Mailer bug #127521: Inline PGP support for evolution (part A: only sending)



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]