[evolution-patches] Mailer bug #127521: Inline PGP support for evolution (sign and signature verification)



This patch implements:

  A) cleartext signing
  B) verification of cleartext signed messages

The code is below, or at:
  http://bugzilla.gnome.org/showattachment.cgi?attach_id=24012

Note:
  There are no ChangeLogs yet. I will add them when I receive comments.

-Bohumir


Index: camel/camel-cipher-context.c
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-cipher-context.c,v
retrieving revision 1.17
diff -u -r1.17 camel-cipher-context.c
--- camel/camel-cipher-context.c	10 Dec 2003 05:25:24 -0000	1.17
+++ camel/camel-cipher-context.c	3 Feb 2004 08:02:39 -0000
@@ -650,3 +650,37 @@
 
 	return res;
 }
+
+/**
+ * camel_cipher_data_wrapper_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_data_wrapper_to_canon_stream (CamelDataWrapper *dw, guint32 flags, CamelStream *ostream)
+{
+	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.15
diff -u -r1.15 camel-cipher-context.h
--- camel/camel-cipher-context.h	10 Dec 2003 05:25:24 -0000	1.15
+++ camel/camel-cipher-context.h	3 Feb 2004 08:02:39 -0000
@@ -183,6 +183,7 @@
 
 /* utility functions */
 int		     camel_cipher_canonical_to_stream(CamelMimePart *part, guint32 flags, CamelStream *ostream);
+int		     camel_cipher_data_wrapper_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.47
diff -u -r1.47 camel-gpg-context.c
--- camel/camel-gpg-context.c	20 Jan 2004 05:32:54 -0000	1.47
+++ camel/camel-gpg-context.c	3 Feb 2004 08:02:39 -0000
@@ -148,7 +148,9 @@
 
 enum _GpgCtxMode {
 	GPG_CTX_MODE_SIGN,
+	GPG_CTX_MODE_CLEARSIGN,
 	GPG_CTX_MODE_VERIFY,
+	GPG_CTX_MODE_CLEARVERIFY,
 	GPG_CTX_MODE_ENCRYPT,
 	GPG_CTX_MODE_DECRYPT,
 	GPG_CTX_MODE_IMPORT,
@@ -296,7 +298,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
@@ -503,6 +505,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 */
@@ -515,6 +529,18 @@
 			g_ptr_array_add (argv, gpg->sigfile);
 		g_ptr_array_add (argv, "-");
 		break;
+	case GPG_CTX_MODE_CLEARVERIFY:
+		if (!camel_session_is_online (gpg->session)) {
+			/* this is a deprecated flag to gpg since 1.0.7 */
+			/*g_ptr_array_add (argv, "--no-auto-key-retrieve");*/
+			g_ptr_array_add (argv, "--keyserver-options");
+			g_ptr_array_add (argv, "no-auto-key-retrieve");
+		}
+		g_ptr_array_add (argv, "--verify");
+		if (gpg->sigfile)
+			g_ptr_array_add (argv, gpg->sigfile);
+		g_ptr_array_add (argv, "-");
+		break;
 	case GPG_CTX_MODE_ENCRYPT:
 		g_ptr_array_add (argv,  "--encrypt");
 		if (gpg->armor)
@@ -821,6 +847,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;
@@ -842,6 +873,27 @@
 				gpg->validsig = FALSE;
 			}
 			break;
+		case GPG_CTX_MODE_CLEARVERIFY:
+			if (!strncmp (status, "TRUST_", 6)) {
+				status += 6;
+				if (!strncmp (status, "NEVER", 5)) {
+					gpg->trust = GPG_TRUST_NEVER;
+				} else if (!strncmp (status, "MARGINAL", 8)) {
+					gpg->trust = GPG_TRUST_MARGINAL;
+				} else if (!strncmp (status, "FULLY", 5)) {
+					gpg->trust = GPG_TRUST_FULLY;
+				} else if (!strncmp (status, "ULTIMATE", 8)) {
+					gpg->trust = GPG_TRUST_ULTIMATE;
+				}
+			} else if (!strncmp (status, "VALIDSIG", 8)) {
+				gpg->validsig = TRUE;
+			} else if (!strncmp (status, "BADSIG", 6)) {
+				gpg->validsig = FALSE;
+			} else if (!strncmp (status, "ERRSIG", 6)) {
+				/* Note: NO_PUBKEY often comes after an ERRSIG, but do we really care? */
+				gpg->validsig = FALSE;
+			}
+			break;
 		case GPG_CTX_MODE_ENCRYPT:
 			if (!strncmp (status, "BEGIN_ENCRYPTION", 16)) {
 				/* nothing to do... but we know to expect data on stdout soon */
@@ -1102,9 +1154,15 @@
 	case GPG_CTX_MODE_SIGN:
 		mode = "sign";
 		break;
+	case GPG_CTX_MODE_CLEARSIGN:
+		mode = "clearsign";
+		break;
 	case GPG_CTX_MODE_VERIFY:
 		mode = "verify";
 		break;
+	case GPG_CTX_MODE_CLEARVERIFY:
+		mode = "clearverify";
+		break;
 	case GPG_CTX_MODE_ENCRYPT:
 		mode = "encrypt";
 		break;
@@ -1464,6 +1522,80 @@
 	return NULL;
 }
 
+CamelCipherValidity *
+camel_gpg_context_clearverify (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
+{
+	CamelCipherValidity *validity;
+	const char *diagnostics = NULL, *tmp;
+	struct _GpgCtx *gpg = NULL;
+	gboolean valid;
+	CamelContentType *ct;
+	CamelStream *istream = NULL;
+
+	if (ipart == NULL) {
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+				      _("Cannot verify message signature: Incorrect message format"));
+		goto exception;
+	}
+
+	ct = camel_mime_part_get_content_type(ipart);
+	tmp = camel_content_type_param(ct, "protocol");
+	if (!camel_content_type_is(ct, "application", "x-inline-pgp-signed")) {
+		/*	    || g_ascii_strcasecmp(tmp, context->sign_protocol) != 0) {*/
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+				      _("Cannot verify message signature: Incorrect message format"));
+		return NULL;
+	}
+
+	istream = camel_stream_mem_new();
+	camel_cipher_canonical_to_stream(ipart, CAMEL_MIME_FILTER_CANON_CRLF, istream);
+	camel_stream_reset(istream);
+	
+	gpg = gpg_ctx_new (context->session);
+	gpg_ctx_set_mode (gpg, GPG_CTX_MODE_CLEARVERIFY);
+	gpg_ctx_set_hash (gpg, camel_cipher_id_to_hash(context, camel_content_type_param(ct, "Hash")));
+	gpg_ctx_set_istream (gpg, istream);
+	
+	if (gpg_ctx_op_start (gpg) == -1) {
+		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM,
+				     _("Failed to execute gpg."));
+		gpg_ctx_free (gpg);
+		goto exception;
+	}
+	
+	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 exception;
+		}
+		
+		if (gpg_ctx_op_step (gpg, ex) == -1) {
+			gpg_ctx_op_cancel (gpg);
+			goto exception;
+		}
+	}
+	
+	valid = gpg_ctx_op_wait (gpg) == 0;
+	validity = camel_cipher_validity_new ();
+	diagnostics = gpg_ctx_get_diagnostics (gpg);
+	camel_cipher_validity_set_valid (validity, valid);
+	camel_cipher_validity_set_description (validity, diagnostics);
+	gpg_ctx_free (gpg);
+	
+	return validity;
+	
+ exception:
+	
+	gpg_ctx_free (gpg);
+
+	if (istream)
+		camel_object_unref(istream);
+
+	return NULL;
+}
+
 static int
 gpg_encrypt (CamelCipherContext *context, const char *userid, GPtrArray *recipients, struct _CamelMimePart *ipart, struct _CamelMimePart *opart, CamelException *ex)
 {
@@ -1747,6 +1879,95 @@
 
 /* ********************************************************************** */
 
+/**
+ * camel_gpg_context_clearsign:
+ * @context: gpg context
+ * @userid: user id
+ * @hash: hash algorithm
+ * @plain: input plain text message
+ * @current: output plain text message with clear text signature added
+ * @ex: exception status
+ *
+ * Sets the @always_trust flag on the gpg context which is used for
+ * encryption.
+ **/
+int
+camel_gpg_context_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelDataWrapper *plain, CamelDataWrapper *current, CamelException *ex)
+{
+	struct _GpgCtx *gpg = NULL;
+	CamelStream *istream, *ostream;
+	CamelContentType *ct;
+	int res = -1;
+
+	/* Note: see rfc2440, section 7 */
+
+	istream = camel_stream_mem_new ();
+	ostream = camel_stream_mem_new ();
+	if (camel_cipher_data_wrapper_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 ("text", "plain");
+	camel_content_type_set_param (ct, "x-action", "pgp-signed");
+	camel_content_type_set_param (ct, "format", "text");
+	camel_data_wrapper_set_mime_type_field (current, ct);
+	camel_content_type_unref (ct);
+
+fail:
+	camel_object_unref (ostream);
+	if (gpg)
+		gpg_ctx_free (gpg);
+	
+	return res;
+}
+
+/* ********************************************************************** */
+
 static void
 camel_gpg_context_class_init (CamelGpgContextClass *klass)
 {
Index: camel/camel-gpg-context.h
===================================================================
RCS file: /cvs/gnome/evolution/camel/camel-gpg-context.h,v
retrieving revision 1.4
diff -u -r1.4 camel-gpg-context.h
--- camel/camel-gpg-context.h	1 Nov 2002 00:45:05 -0000	1.4
+++ camel/camel-gpg-context.h	3 Feb 2004 08:02:39 -0000
@@ -57,6 +57,11 @@
 
 void camel_gpg_context_set_always_trust (CamelGpgContext *ctx, gboolean trust);
 
+int camel_gpg_context_clearsign (CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelDataWrapper *plain, CamelDataWrapper *current, CamelException *ex);
+
+CamelCipherValidity *
+camel_gpg_context_clearverify (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: composer/e-msg-composer.c
===================================================================
RCS file: /cvs/gnome/evolution/composer/e-msg-composer.c,v
retrieving revision 1.435
diff -u -r1.435 e-msg-composer.c
--- composer/e-msg-composer.c	2 Feb 2004 05:05:05 -0000	1.435
+++ composer/e-msg-composer.c	3 Feb 2004 08:02:39 -0000
@@ -371,10 +371,11 @@
 	CamelMimeMessage *new;
 	const char *charset = NULL;
 	CamelStream *stream;
-	CamelMimePart *part;
+	CamelMimePart *part = NULL;
 	CamelException ex;
 	GByteArray *data;
 	int i;
+	gboolean clearsign_applied = FALSE;
 	
 	if (composer->persist_stream_interface == CORBA_OBJECT_NIL)
 		return NULL;
@@ -579,12 +580,7 @@
 		const char *pgp_userid;
 		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);
+		gboolean mimesign = FALSE;
 
 		if (hdrs->account && hdrs->account->pgp_key && *hdrs->account->pgp_key) {
 			pgp_userid = hdrs->account->pgp_key;
@@ -593,23 +589,68 @@
 			camel_internet_address_get(from, 0, NULL, &pgp_userid);
 		}
 		
-		if (composer->pgp_sign) {
-			CamelMimePart *npart = camel_mime_part_new();
+		if (composer->pgp_sign && hdrs->account->pgp_clearsign) {
 
-			cipher = mail_crypto_get_pgp_cipher_context(hdrs->account);
-			camel_cipher_sign(cipher, pgp_userid, CAMEL_CIPHER_HASH_SHA1, part, npart, &ex);
-			camel_object_unref(cipher);
-			
-			if (camel_exception_is_set(&ex)) {
-				camel_object_unref(npart);
+			if ((current == plain) && !composer->pgp_encrypt) {
+				/* do clearsign */
+				current = camel_data_wrapper_new ();
+
+				cipher = mail_crypto_get_pgp_cipher_context (hdrs->account);
+				camel_gpg_context_clearsign (cipher, pgp_userid, CAMEL_CIPHER_HASH_SHA1, plain, current, &ex);
+				clearsign_applied = TRUE;
+				camel_object_unref (cipher);
+
+				if (camel_exception_is_set (&ex)) {
+					camel_object_unref (current);
+					goto exception;
+				}
+			}
+			else  {
+				/* offer mimesign */
+				mimesign = em_utils_prompt_user ((GtkWindow *) composer, GTK_RESPONSE_YES, NULL,
+								 _("PGP clearsign can only be used for plain text message without encryption.\nUse MIME signature instead?\n"));
+			}
+		}
+
+		mimesign = mimesign || (composer->pgp_sign && !hdrs->account->pgp_clearsign);
+
+		if (mimesign) {
+			/* do mimesign */
+			part = camel_mime_part_new ();
+
+			camel_medium_set_content_object (CAMEL_MEDIUM (part), current);
+			camel_object_unref (current);
+
+			CamelMimePart *npart = camel_mime_part_new ();
+
+			cipher = mail_crypto_get_pgp_cipher_context (hdrs->account);
+			camel_cipher_sign (cipher, pgp_userid, CAMEL_CIPHER_HASH_SHA1, part, npart, &ex);
+			camel_object_unref (cipher);
+
+			if (camel_exception_is_set (&ex)) {
+				camel_object_unref (npart);
 				goto exception;
 			}
 
 			camel_object_unref(part);
 			part = npart;
+
+			current = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+			camel_object_ref (current);
+
+			if (!composer->pgp_encrypt)
+				camel_object_unref (part);
 		}
 		
 		if (composer->pgp_encrypt) {
+			/* if mimesign was done, we will encrypt "part" created there,
+			 * otherwise we need to create a new "part" from "current" */
+			if (!mimesign) {
+				part = camel_mime_part_new ();
+				camel_medium_set_content_object (CAMEL_MEDIUM (part), current);
+				camel_object_unref (current);
+			}
+
 			CamelMimePart *npart = camel_mime_part_new();
 
 			/* check to see if we should encrypt to self, NB gets removed immediately after use */
@@ -630,14 +671,16 @@
 
 			camel_object_unref (part);
 			part = npart;
+
+			current = camel_medium_get_content_object (CAMEL_MEDIUM (part));
+			camel_object_ref (current);
+
+			camel_object_unref (part);
 		}
 
 		if (from)
 			camel_object_unref (from);	
 	
-		current = camel_medium_get_content_object (CAMEL_MEDIUM (part));
-		camel_object_ref (current);
-		camel_object_unref (part);
 	}
 	
 #if defined (HAVE_NSS) && defined (SMIME_SUPPORTED)
@@ -722,7 +765,7 @@
 #endif /* HAVE_NSS */
 
 	camel_medium_set_content_object (CAMEL_MEDIUM (new), current);
-	if (current == plain)
+	if ((current == plain) || clearsign_applied)
 		camel_mime_part_set_encoding (CAMEL_MIME_PART (new), plain_encoding);
 	camel_object_unref (current);
 
@@ -742,7 +785,7 @@
 	
  exception:
 	
-	if (part != CAMEL_MIME_PART (new))
+	if ((part != CAMEL_MIME_PART (new)) && (part != NULL))
 		camel_object_unref (part);
 	
 	camel_object_unref (new);
Index: e-util/e-account.c
===================================================================
RCS file: /cvs/gnome/evolution/e-util/e-account.c,v
retrieving revision 1.6
diff -u -r1.6 e-account.c
--- e-util/e-account.c	14 Jan 2004 17:29:24 -0000	1.6
+++ e-util/e-account.c	3 Feb 2004 08:02:39 -0000
@@ -329,6 +329,7 @@
 			changed |= xml_set_bool (node, "encrypt-to-self", &account->pgp_encrypt_to_self);
 			changed |= xml_set_bool (node, "always-trust", &account->pgp_always_trust);
 			changed |= xml_set_bool (node, "always-sign", &account->pgp_always_sign);
+			changed |= xml_set_bool (node, "clearsign", &account->pgp_clearsign);
 			changed |= xml_set_bool (node, "no-imip-sign", &account->pgp_no_imip_sign);
 
 			if (node->children) {
@@ -418,6 +419,7 @@
 	dest->pgp_key = g_strdup (src->pgp_key);
 	dest->pgp_encrypt_to_self = src->pgp_encrypt_to_self;
 	dest->pgp_always_sign = src->pgp_always_sign;
+	dest->pgp_clearsign = src->pgp_clearsign;
 	dest->pgp_no_imip_sign = src->pgp_no_imip_sign;
 	dest->pgp_always_trust = src->pgp_always_trust;
 	
@@ -503,6 +505,7 @@
 	xmlSetProp (node, "encrypt-to-self", account->pgp_encrypt_to_self ? "true" : "false");
 	xmlSetProp (node, "always-trust", account->pgp_always_trust ? "true" : "false");
 	xmlSetProp (node, "always-sign", account->pgp_always_sign ? "true" : "false");
+	xmlSetProp (node, "clearsign", account->pgp_clearsign ? "true" : "false");
 	xmlSetProp (node, "no-imip-sign", account->pgp_no_imip_sign ? "true" : "false");
 	if (account->pgp_key)
 		xmlNewTextChild (node, NULL, "key-id", account->pgp_key);
Index: e-util/e-account.h
===================================================================
RCS file: /cvs/gnome/evolution/e-util/e-account.h,v
retrieving revision 1.4
diff -u -r1.4 e-account.h
--- e-util/e-account.h	31 Oct 2003 04:55:41 -0000	1.4
+++ e-util/e-account.h	3 Feb 2004 08:02:39 -0000
@@ -69,6 +69,7 @@
 	char *pgp_key;
 	gboolean pgp_encrypt_to_self;
 	gboolean pgp_always_sign;
+	gboolean pgp_clearsign;
 	gboolean pgp_no_imip_sign;
 	gboolean pgp_always_trust;
 
Index: mail/em-format-html-display.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format-html-display.c,v
retrieving revision 1.25
diff -u -r1.25 em-format-html-display.c
--- mail/em-format-html-display.c	30 Jan 2004 03:10:14 -0000	1.25
+++ mail/em-format-html-display.c	3 Feb 2004 08:02:40 -0000
@@ -843,8 +843,16 @@
 static void
 efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
 {
-	/* Note: We call EMFormatClass directly, not EMFormatHTML, our parent */
-	efhd_format_class->format_secure(emf, stream, part, valid);
+	CamelContentType *type;
+
+	type = camel_mime_part_get_content_type(part);
+	if (!camel_content_type_is (type, "application", "x-inline-pgp-signed")) {
+		/* Note: We call EMFormatClass directly, not EMFormatHTML, our parent */
+		efhd_format_class->format_secure(emf, stream, part, valid);
+	}
+	else {
+		emf->valid = valid;
+	}
 
 	if (emf->valid == valid
 	    && (valid->encrypt.status != CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE
Index: mail/em-format-html.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format-html.c,v
retrieving revision 1.31
diff -u -r1.31 em-format-html.c
--- mail/em-format-html.c	30 Jan 2004 03:10:14 -0000	1.31
+++ mail/em-format-html.c	3 Feb 2004 08:02:40 -0000
@@ -579,7 +579,27 @@
 static void
 efh_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
 {
-	efh_parent->format_secure(emf, stream, part, valid);
+	CamelContentType *type;
+	type = camel_mime_part_get_content_type(part);
+	if (camel_content_type_is (type, "application", "x-inline-pgp-signed")) {
+
+		CamelStreamFilter *filtered_stream;
+		CamelMimeFilter *html_filter;
+		guint32 rgb = 0x737373, flags;
+
+		filtered_stream = camel_stream_filter_new_with_stream(stream);
+
+		flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
+			CAMEL_MIME_FILTER_TOHTML_MARK_CITATION;
+		html_filter = camel_mime_filter_tohtml_new(flags, rgb);
+		camel_stream_filter_add(filtered_stream, html_filter);
+		camel_object_unref(html_filter);
+
+		efh_parent->format_secure(emf, (CamelStream*) filtered_stream, part, valid);
+	}
+	else {
+		efh_parent->format_secure(emf, stream, part, valid);
+	}
 
 	/* To explain, if the validity is the same, then we are the
 	   base validity and now have a combined sign/encrypt validity
@@ -701,6 +721,18 @@
 			em_format_format_text((EMFormat *)efh, (CamelStream *)filtered_stream, camel_medium_get_content_object((CamelMedium *)newpart));
 			camel_stream_flush((CamelStream *)filtered_stream);
 			camel_stream_write_string(stream, "</tt>\n");
+		}
+		else if (camel_content_type_is (type, "application", "x-inline-pgp-signed")) {
+
+			/* first write as simple text */
+			camel_stream_write_string(stream, "<tt>\n");
+			em_format_format_text((EMFormat *)efh, (CamelStream *)filtered_stream, camel_medium_get_content_object((CamelMedium *)newpart));
+			camel_stream_flush((CamelStream *)filtered_stream);
+			camel_stream_write_string(stream, "</tt>\n");
+
+			/* then investigate validity and notify user */
+			em_format_part((EMFormat *)efh, stream, newpart);
+			
 		} else {
 			g_string_append_printf(((EMFormat *)efh)->part_id, ".inline.%d", i);
 			em_format_part((EMFormat *)efh, stream, newpart);
Index: mail/em-format.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format.c,v
retrieving revision 1.23
diff -u -r1.23 em-format.c
--- mail/em-format.c	30 Jan 2004 03:10:14 -0000	1.23
+++ mail/em-format.c	3 Feb 2004 08:02:40 -0000
@@ -586,6 +586,7 @@
 {
 	CamelCipherValidity *save = emf->valid_parent;
 	int len;
+	CamelContentType *type;
 
 	/* Note that this also requires support from higher up in the class chain
 	    - validity needs to be cleared when you start output
@@ -600,10 +601,19 @@
 
 	emf->valid_parent = valid;
 
-	len = emf->part_id->len;
-	g_string_append_printf(emf->part_id, ".secured");
-	em_format_part(emf, stream, part);
-	g_string_truncate(emf->part_id, len);
+	type = camel_mime_part_get_content_type(part);
+	if (camel_content_type_is (type, "application", "x-inline-pgp-signed")) {
+		camel_stream_write_string(stream, "<tt>\n");
+		em_format_format_text(emf, stream, camel_medium_get_content_object((CamelMedium *)part));
+		camel_stream_flush((CamelStream *)stream);
+		camel_stream_write_string(stream, "</tt>\n");
+	}
+	else {
+		len = emf->part_id->len;
+		g_string_append_printf(emf->part_id, ".secured");
+		em_format_part(emf, stream, part);
+		g_string_truncate(emf->part_id, len);
+	}
 
 	emf->valid_parent = save;
 }
@@ -813,6 +823,7 @@
 	return !(camel_content_type_is (dw->mime_type, "multipart", "*")
 		 || camel_content_type_is(dw->mime_type, "application", "x-pkcs7-mime")
 		 || camel_content_type_is(dw->mime_type, "application", "pkcs7-mime")
+		 || camel_content_type_is(dw->mime_type, "application", "x-inline-pgp-signed")
 		 || (camel_content_type_is (dw->mime_type, "text", "*")
 		     && camel_mime_part_get_filename(part) == NULL));
 }
@@ -1052,6 +1063,33 @@
 }
 #endif
 
+static void
+emf_inline_pgp_signed (EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+	CamelCipherContext *cipher = NULL;
+
+	cipher = camel_gpg_context_new(emf->session);
+
+	if (cipher == NULL) {
+		em_format_format_error(emf, stream, _("Unsupported signature format"));
+		em_format_part_as(emf, stream, part, NULL);
+	} else {
+		CamelException *ex = camel_exception_new();
+		CamelCipherValidity *valid;
+
+		valid = camel_gpg_context_clearverify(cipher, part, ex);
+		if (valid == NULL) {
+			em_format_format_error(emf, stream, ex->desc?ex->desc:_("Unknown error verifying signature"));
+			em_format_part_as(emf, stream, part, NULL);
+		} else {
+			em_format_format_secure(emf, stream, part, valid);
+		}
+
+		camel_exception_free(ex);
+		camel_object_unref(cipher);
+	}
+}
+
 /* RFC 1740 */
 static void
 emf_multipart_appledouble(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
@@ -1350,6 +1388,7 @@
 #ifdef HAVE_NSS
 	{ "application/x-pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime },
 #endif
+	{ "application/x-inline-pgp-signed", (EMFormatFunc)emf_inline_pgp_signed },
 	{ "multipart/alternative", emf_multipart_alternative },
 	{ "multipart/appledouble", emf_multipart_appledouble },
 	{ "multipart/encrypted", emf_multipart_encrypted },
Index: mail/em-inline-filter.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-inline-filter.c,v
retrieving revision 1.4
diff -u -r1.4 em-inline-filter.c
--- mail/em-inline-filter.c	9 Jan 2004 02:06:02 -0000	1.4
+++ mail/em-inline-filter.c	3 Feb 2004 08:02:40 -0000
@@ -110,7 +110,7 @@
 	{ "application/octet-stream", CAMEL_TRANSFER_ENCODING_UUENCODE, },
 	{ "application/mac-binhex40", CAMEL_TRANSFER_ENCODING_7BIT, },
 	{ "application/postscript", CAMEL_TRANSFER_ENCODING_7BIT, },
-	{ "text/plain", CAMEL_TRANSFER_ENCODING_7BIT, 1, },
+	{ "application/x-inline-pgp-signed", CAMEL_TRANSFER_ENCODING_7BIT, },
 };
 
 static void
@@ -206,16 +206,11 @@
 				emif_add_part(emif, data_start, start-data_start);
 				data_start = start;
 				emif->state = EMIF_POSTSCRIPT;
-#if 0
-/* This should be hooked in once someone can work out how to handle it.
-   Maybe we need a multipart_gpg_inline_signed or some crap, if it
-   can't be converted to a real multipart/signed */
 			} else if (strncmp(start, "-----BEGIN PGP SIGNED MESSAGE-----", 34) == 0) {
 				inptr[-1] = '\n';
 				emif_add_part(emif, data_start, start-data_start);
 				data_start = start;
 				emif->state = EMIF_PGPSIGNED;
-#endif
 			}
 			break;
 		case EMIF_UUENC:
@@ -243,7 +238,6 @@
 			}
 			break;
 		case EMIF_PGPSIGNED:
-			/* This is currently a noop - it just turns it into a text part */
 			if (strcmp(start, "-----END PGP SIGNATURE-----") == 0) {
 				inptr[-1] = '\n';
 				emif_add_part(emif, data_start, inptr-data_start);
Index: mail/em-migrate.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-migrate.c,v
retrieving revision 1.32
diff -u -r1.32 em-migrate.c
--- mail/em-migrate.c	27 Jan 2004 22:51:00 -0000	1.32
+++ mail/em-migrate.c	3 Feb 2004 08:02:40 -0000
@@ -718,6 +718,7 @@
 	{ "account_pgp_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
 	{ "account_pgp_always_trust_%i", "always-trust", E_BCONF_MAP_BOOL },
 	{ "account_pgp_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
+	{ "account_pgp_clearsign_%i", "clearsign", E_BCONF_MAP_BOOL },
 	{ "account_pgp_no_imip_sign_%i", "no-imip-sign", E_BCONF_MAP_BOOL },
 	{ "account_pgp_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
 	{ NULL },
Index: mail/mail-account-editor.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-account-editor.c,v
retrieving revision 1.59
diff -u -r1.59 mail-account-editor.c
--- mail/mail-account-editor.c	1 Dec 2003 01:32:24 -0000	1.59
+++ mail/mail-account-editor.c	3 Feb 2004 08:02:40 -0000
@@ -199,6 +199,7 @@
 	g_signal_connect (editor->gui->pgp_key, "changed", G_CALLBACK (mail_account_editor_changed), editor);
 	g_signal_connect (editor->gui->pgp_encrypt_to_self, "toggled", G_CALLBACK (mail_account_editor_changed), editor);
 	g_signal_connect (editor->gui->pgp_always_sign, "toggled", G_CALLBACK (mail_account_editor_changed), editor);
+	g_signal_connect (editor->gui->pgp_clearsign, "toggled", G_CALLBACK (mail_account_editor_changed), editor);
 	g_signal_connect (editor->gui->pgp_no_imip_sign, "toggled", G_CALLBACK (mail_account_editor_changed), editor);
 	g_signal_connect (editor->gui->pgp_always_trust, "toggled", G_CALLBACK (mail_account_editor_changed), editor);
 
Index: mail/mail-account-gui.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-account-gui.c,v
retrieving revision 1.146
diff -u -r1.146 mail-account-gui.c
--- mail/mail-account-gui.c	30 Jan 2004 22:16:48 -0000	1.146
+++ mail/mail-account-gui.c	3 Feb 2004 08:02:40 -0000
@@ -1624,6 +1624,8 @@
 	gtk_toggle_button_set_active (gui->pgp_encrypt_to_self, account->pgp_encrypt_to_self);
 	gui->pgp_always_sign = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_always_sign"));
 	gtk_toggle_button_set_active (gui->pgp_always_sign, account->pgp_always_sign);
+	gui->pgp_clearsign = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_clearsign"));
+	gtk_toggle_button_set_active (gui->pgp_clearsign, account->pgp_clearsign);
 	gui->pgp_no_imip_sign = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_no_imip_sign"));
 	gtk_toggle_button_set_active (gui->pgp_no_imip_sign, account->pgp_no_imip_sign);
 	gui->pgp_always_trust = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "pgp_always_trust"));
@@ -2029,6 +2031,7 @@
 	new->pgp_key = g_strdup (gtk_entry_get_text (gui->pgp_key));
 	new->pgp_encrypt_to_self = gtk_toggle_button_get_active (gui->pgp_encrypt_to_self);
 	new->pgp_always_sign = gtk_toggle_button_get_active (gui->pgp_always_sign);
+	new->pgp_clearsign = gtk_toggle_button_get_active (gui->pgp_clearsign);
 	new->pgp_no_imip_sign = gtk_toggle_button_get_active (gui->pgp_no_imip_sign);
 	new->pgp_always_trust = gtk_toggle_button_get_active (gui->pgp_always_trust);
 	
Index: mail/mail-account-gui.h
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-account-gui.h,v
retrieving revision 1.26
diff -u -r1.26 mail-account-gui.h
--- mail/mail-account-gui.h	31 Oct 2003 04:56:46 -0000	1.26
+++ mail/mail-account-gui.h	3 Feb 2004 08:02:40 -0000
@@ -106,6 +106,7 @@
 	GtkEntry *pgp_key;
 	GtkToggleButton *pgp_encrypt_to_self;
 	GtkToggleButton *pgp_always_sign;
+	GtkToggleButton *pgp_clearsign;
 	GtkToggleButton *pgp_no_imip_sign;
 	GtkToggleButton *pgp_always_trust;
 
Index: mail/mail-config.glade
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-config.glade,v
retrieving revision 1.129
diff -u -r1.129 mail-config.glade
--- mail/mail-config.glade	23 Jan 2004 17:21:42 -0000	1.129
+++ mail/mail-config.glade	3 Feb 2004 08:02:41 -0000
@@ -2644,6 +2644,24 @@
 		      </child>
 
 		      <child>
+			<widget class="GtkCheckButton" id="pgp_clearsign">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">When signing outgoing message, use _cleartext signature if possible</property>
+			  <property name="use_underline">True</property>
+			  <property name="relief">GTK_RELIEF_NORMAL</property>
+			  <property name="active">False</property>
+			  <property name="inconsistent">False</property>
+			  <property name="draw_indicator">True</property>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
 			<widget class="GtkCheckButton" id="pgp_no_imip_sign">
 			  <property name="visible">True</property>
 			  <property name="can_focus">True</property>



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