[evolution-patches] Bug 217540: Implementation of inline PGP receive support



Hi, 

Please find attached 3 patches to implement support for processing and
displaying received inline PGP signed or encrypted messages. This is
bounty #127521 and fixes bug #217540. I have chosen not to implement
support for sending inline PGP messages, It's a pretty broken format and
evo supports PGP/MIME I don't see any need for it.

The patches are as follow and can also be found at
http://www.mattb.net.nz/patches/evolution/.

eds-inlinepgp-final.patch

Adds support to the backend to decrypt and verify inline PGP messages
via two mime parts that are created by the inline-filter in the mailer.
Also implements a camel-mime-filter to strip dash encoding from inline
signed messages. 

 2005-06-24	Matt Brown <matt mattb net nz>

	* camel-gpg-context.c:	Extend verify and decrypt functions to support
	inline pgp signed messages via x-inlinepgp-signed/x-inlinepgp-encrypted
	mime types.
	* camel-mime-filter-pgp.h:
	* camel-mime-filter-pgp.c:
	New filter to strip dash encoding from inline pgp signed messages.


evo-inlinepgp-final.patch

Adds the necessary support to the mailer. 
* Extends the inline filter to detect inline PGP message parts and
creates the appropriate mime parts.
* Implements format routines to pass the parts to the appropriate
functions in the backend and display the verified/decrypted result. 

2005-06-24	Matt Brown	<matt mattb net nz>

	* em-inline-filter.c: implement extraction of inline signed/encrypted pgp
	parts and package them into x-inlinepgp-signed/x-inline-pgp-encrypted
	parts.
	* em-format-html.c: Formatters to verify/decrypt and then display the
	parts generated by the inline filter.

evo-inlinepgp-formatchanges.patch

Makes minor modifications to the way inline parts generated by the
inline filter are displayed. Without this patch the generate mime parts
for inline pgp messages display inside a grey border and do not appear
as a normal main message. 

Michael Zucchi has expressed some reservations about this part of the
patch, so I've seperated it out for ease of review. The full
functionality of inline pgp support is provided without this patch, the
display is just a little funny. 

Please apply these patches :)

They've been through several review cycles by Jeffrey Steadfast and
Michael Zucchi on the -hackers mailing list so I'm hoping there are no
remaining problems with them. 

Kind Regards

-- 
Matt Brown
matt mattb net nz
Mob +64 275 611 544 www.mattb.net.nz
Index: camel/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/ChangeLog,v
retrieving revision 1.2450
diff -u -p -r1.2450 ChangeLog
--- camel/ChangeLog	9 Jun 2005 07:00:23 -0000	1.2450
+++ camel/ChangeLog	24 Jun 2005 09:01:56 -0000
@@ -1,3 +1,12 @@
+2005-06-24	Matt Brown <matt mattb net nz>
+
+	* camel-gpg-context.c:	Extend verify and decrypt functions to support
+	inline pgp signed messages via x-inlinepgp-signed/x-inlinepgp-encrypted
+	mime types.
+	* camel-mime-filter-pgp.h:
+	* camel-mime-filter-pgp.c:
+	New filter to strip dash encoding from inline pgp signed messages.
+
 2005-06-09  Sarfraaz Ahmed <asarfraaz novell com>
 
 	* camel-store.c (camel_folder_info_build): Minor typo in debug message.
Index: camel/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/Makefile.am,v
retrieving revision 1.209
diff -u -p -r1.209 Makefile.am
--- camel/Makefile.am	11 Apr 2005 12:21:29 -0000	1.209
+++ camel/Makefile.am	24 Jun 2005 09:01:57 -0000
@@ -156,6 +156,7 @@ libcamel_1_2_la_SOURCES = 				\
 	camel-mime-filter-html.c		\
 	camel-mime-filter-index.c		\
 	camel-mime-filter-linewrap.c		\
+	camel-mime-filter-pgp.c			\
 	camel-mime-filter-save.c		\
 	camel-mime-filter-tohtml.c		\
 	camel-mime-filter-windows.c		\
@@ -223,6 +224,7 @@ libcamelinclude_HEADERS =			\
 	camel-mime-filter-html.h		\
 	camel-mime-filter-index.h		\
 	camel-mime-filter-linewrap.h		\
+	camel-mime-filter-pgp.h			\
 	camel-mime-filter-save.h		\
 	camel-mime-filter-tohtml.h		\
 	camel-mime-filter-windows.h		\
Index: camel/camel-gpg-context.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/camel/camel-gpg-context.c,v
retrieving revision 1.71
diff -u -p -r1.71 camel-gpg-context.c
--- camel/camel-gpg-context.c	5 May 2005 18:38:48 -0000	1.71
+++ camel/camel-gpg-context.c	24 Jun 2005 09:02:01 -0000
@@ -1358,7 +1358,7 @@ static CamelCipherValidity *
 gpg_verify (CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex)
 {
 	CamelCipherValidity *validity;
-	const char *diagnostics = NULL, *tmp;
+	const char *diagnostics = NULL;
 	struct _GpgCtx *gpg = NULL;
 	char *sigfile = NULL;
 	CamelContentType *ct;
@@ -1368,29 +1368,52 @@ gpg_verify (CamelCipherContext *context,
 
 	mps = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)ipart);
 	ct = ((CamelDataWrapper *)mps)->mime_type;
-	tmp = camel_content_type_param(ct, "protocol");
-	if (!camel_content_type_is(ct, "multipart", "signed")
-	    || !CAMEL_IS_MULTIPART_SIGNED(mps)
-	    || tmp == NULL
-	    || g_ascii_strcasecmp(tmp, context->sign_protocol) != 0) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+	
+	/* Inline signature (using our fake mime type) or PGP/Mime signature */
+	if (camel_content_type_is(ct, "multipart", "signed")) {
+		/* PGP/Mime Signature */
+		const char *tmp;
+
+		tmp = camel_content_type_param(ct, "protocol");
+		if (!CAMEL_IS_MULTIPART_SIGNED(mps)
+		    || tmp == NULL  
+		    || g_ascii_strcasecmp(tmp, context->sign_protocol) != 0) {
+			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot verify message signature: Incorrect message format"));
-		return NULL;
-	}
-
-	if (!(istream = camel_multipart_signed_get_content_stream ((CamelMultipartSigned *) mps, NULL))) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+			return NULL;
+		}
+	
+		if (!(istream = camel_multipart_signed_get_content_stream ((CamelMultipartSigned *) mps, NULL))) {
+			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot verify message signature: Incorrect message format"));
-		return NULL;
-	}
+			return NULL;
+		}
 	
-	if (!(sigpart = camel_multipart_get_part (mps, CAMEL_MULTIPART_SIGNED_SIGNATURE))) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+		if (!(sigpart = camel_multipart_get_part (mps, CAMEL_MULTIPART_SIGNED_SIGNATURE))) {
+			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot verify message signature: Incorrect message format"));
-		camel_object_unref (istream);
+			camel_object_unref (istream);
+			return NULL;
+		}
+
+	} else if (camel_content_type_is(ct, "application", "x-inlinepgp-signed")) {
+		/* Inline Signed */
+		CamelDataWrapper *content;
+		content = camel_medium_get_content_object ((CamelMedium *) ipart);
+		istream = camel_stream_mem_new();
+		camel_data_wrapper_decode_to_stream (content, istream);
+		camel_stream_reset(istream);
+		sigpart = NULL;
+			
+	} else {
+		/* Invalid Mimetype */
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+			      _("Cannot verify message signature: Incorrect message format"));
 		return NULL;
 	}
+    
 
+	/* Now start the real work of verifying the message */
 #ifdef GPG_LOG
 	if (camel_debug_start("gpg:sign")) {
 		char *name;
@@ -1405,31 +1428,35 @@ gpg_verify (CamelCipherContext *context,
 			camel_object_unref(out);
 		}
 		g_free(name);
-		name = g_strdup_printf("camel-gpg.%d.verify.signature", logid++);
-		out = camel_stream_fs_new_with_name(name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
-		if (out) {
-			printf("Writing gpg verify signature to '%s'\n", name);
-			camel_data_wrapper_write_to_stream((CamelDataWrapper *)sigpart, out);
-			camel_object_unref(out);
+		if (sigpart) {
+			name = g_strdup_printf("camel-gpg.%d.verify.signature", logid++);
+			out = camel_stream_fs_new_with_name(name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+			if (out) {
+				printf("Writing gpg verify signature to '%s'\n", name);
+				camel_data_wrapper_write_to_stream((CamelDataWrapper *)sigpart, out);
+				camel_object_unref(out);
+			}
+			g_free(name);
 		}
-		g_free(name);
 		camel_debug_end();
 	}
 #endif
-	
-	sigfile = swrite (sigpart);
-	if (sigfile == NULL) {
-		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+
+	if (sigpart) {
+		sigfile = swrite (sigpart);
+		if (sigfile == NULL) {
+			camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
 				      _("Cannot verify message signature: could not create temp file: %s"),
 				      g_strerror (errno));
-		goto exception;
+			goto exception;
+		}
 	}
 	
 	camel_stream_reset(istream);
 	gpg = gpg_ctx_new (context->session);
 	gpg_ctx_set_mode (gpg, GPG_CTX_MODE_VERIFY);
-	gpg_ctx_set_hash (gpg, camel_cipher_id_to_hash(context, camel_content_type_param(ct, "micalg")));
-	gpg_ctx_set_sigfile (gpg, sigfile);
+	if (sigfile)
+                gpg_ctx_set_sigfile (gpg, sigfile);
 	gpg_ctx_set_istream (gpg, istream);
 	
 	if (gpg_ctx_op_start (gpg) == -1) {
@@ -1464,6 +1491,7 @@ gpg_verify (CamelCipherContext *context,
 		unlink (sigfile);
 		g_free (sigfile);
 	}
+	camel_object_unref(istream);
 	
 	return validity;
 	
@@ -1597,15 +1625,31 @@ gpg_decrypt(CamelCipherContext *context,
 	CamelDataWrapper *content;
 	CamelMimePart *encrypted;
 	CamelMultipart *mp;
+	CamelContentType *ct;
+	int rv;
 	
-	mp = (CamelMultipart *) camel_medium_get_content_object ((CamelMedium *) ipart);
-	if (!(encrypted = camel_multipart_get_part (mp, CAMEL_MULTIPART_ENCRYPTED_CONTENT))) {
-		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to decrypt MIME part: protocol error"));
+	ct = camel_mime_part_get_content_type(ipart);
+	/* Encrypted part (using our fake mime type) or PGP/Mime multipart */
+	if (camel_content_type_is(ct, "multipart", "encrypted")) {
+	
+		mp = (CamelMultipart *) camel_medium_get_content_object ((CamelMedium *) ipart);
+		if (!(encrypted = camel_multipart_get_part (mp, CAMEL_MULTIPART_ENCRYPTED_CONTENT))) {
+			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to decrypt MIME part: protocol error"));
+			return NULL;
+		}
+		
+		content = camel_medium_get_content_object ((CamelMedium *) encrypted);
+
+	} else if (camel_content_type_is(ct, "application", "x-inlinepgp-encrypted")) {
+		content = camel_medium_get_content_object ((CamelMedium *) ipart);
+
+	} else {
+		/* Invalid Mimetype */
+		camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+				_("Cannot decrypt message: Incorrect message format"));
 		return NULL;
 	}
 	
-	content = camel_medium_get_content_object ((CamelMedium *) encrypted);
-	
 	istream = camel_stream_mem_new();
 	camel_data_wrapper_decode_to_stream (content, istream);
 	camel_stream_reset(istream);
@@ -1640,7 +1684,21 @@ gpg_decrypt(CamelCipherContext *context,
 	}
 
 	camel_stream_reset(ostream);
-	if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream) != -1) {
+	if (camel_content_type_is(ct, "multipart", "encrypted")) {
+		/* Multipart encrypted - parse a full mime part */
+		rv = camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream);
+	} else {
+		/* Inline signed - raw data (may not be a mime part) */
+		CamelDataWrapper *dw;
+		dw = camel_data_wrapper_new ();
+		rv = camel_data_wrapper_construct_from_stream(dw, ostream);
+		camel_data_wrapper_set_mime_type(dw, "application/octet-stream");
+		camel_medium_set_content_object((CamelMedium *)opart, dw);
+		camel_object_unref(dw);
+		/* Set mime/type of this new part to application/octet-stream to force type snooping */
+		camel_mime_part_set_content_type(opart, "application/octet-stream");
+	}
+	if (rv != -1) {	
 		valid = camel_cipher_validity_new();
 		valid->encrypt.description = g_strdup(_("Encrypted content"));
 		valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
--- /dev/null	2005-06-24 17:28:39.844700400 +1200
+++ camel/camel-mime-filter-pgp.c	2005-06-13 23:40:29.000000000 +1200
@@ -0,0 +1,165 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005 Matt Brown.
+ *
+ * Authors: Matt Brown <matt mattb net nz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Strips PGP message headers from the input stream and also performs
+ * pgp decoding as described in section 7.1 of RFC2440 */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include "camel-mime-filter-pgp.h"
+
+static void filter (CamelMimeFilter *f, char *in, size_t len, size_t prespace,
+		    char **out, size_t *outlen, size_t *outprespace);
+static void complete (CamelMimeFilter *f, char *in, size_t len,
+		      size_t prespace, char **out, size_t *outlen,
+		      size_t *outprespace);
+static void reset (CamelMimeFilter *f);
+
+enum {
+	PGPF_HEADER,
+	PGPF_MESSAGE,
+	PGPF_FOOTER,
+};
+
+static void
+camel_mime_filter_pgp_class_init (CamelMimeFilterPgpClass *klass)
+{
+	CamelMimeFilterClass *mime_filter_class = (CamelMimeFilterClass *) klass;
+	
+	mime_filter_class->filter = filter;
+	mime_filter_class->complete = complete;
+	mime_filter_class->reset = reset;
+}
+
+CamelType
+camel_mime_filter_pgp_get_type (void)
+{
+	static CamelType type = CAMEL_INVALID_TYPE;
+	
+	if (type == CAMEL_INVALID_TYPE) {
+		type = camel_type_register (camel_mime_filter_get_type(), "CamelMimeFilterPgp",
+					    sizeof (CamelMimeFilterPgp),
+					    sizeof (CamelMimeFilterPgpClass),
+					    (CamelObjectClassInitFunc) camel_mime_filter_pgp_class_init,
+					    NULL,
+					    NULL,
+					    NULL);
+	}
+	
+	return type;
+}
+
+static void
+filter_run(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace, int last)
+{
+	CamelMimeFilterPgp *pgpfilter = (CamelMimeFilterPgp *)f;
+	char *inptr, *inend;
+	register char *o;
+	char *start = in;
+	int tmplen;
+	
+	/* only need as much space as the input, we're stripping chars */
+	camel_mime_filter_set_size(f, len, FALSE);
+
+	o = f->outbuf;
+	inptr = in;
+	inend = in+len;
+	while (inptr < inend) {
+		start = inptr;
+
+		while (inptr < inend && *inptr != '\n')
+			inptr++;
+			
+		if (inptr == inend) {
+			if (!last) {
+				camel_mime_filter_backup(f, start, inend-start);
+				inend = start;
+			}
+			break;
+		}
+
+		*inptr++ = 0;
+		
+		switch (pgpfilter->state) {
+		case PGPF_HEADER:
+			/* Wait for a blank line */
+			if (strlen(start)==0)
+				pgpfilter->state = PGPF_MESSAGE;
+			break;
+		case PGPF_MESSAGE:
+			/* In the message body, check for end of body */
+			if (strncmp(start, "-----", 5)==0) {
+				pgpfilter->state = PGPF_FOOTER;
+				break;
+			}			
+			/* do dash decoding */
+			if (strncmp(start, "- ", 2)==0) {
+				/* Dash encoded line found, skip encoding */
+				start+=2;
+			}
+			tmplen=strlen(start)+1;
+			inptr[-1] = '\n';
+			strncpy(o, start, tmplen);
+			o+=tmplen;	
+			break;
+		case PGPF_FOOTER:
+			/* After end of message, (ie signature or something) skip it */
+			break;
+		}
+		inptr[-1] = '\n';
+	}
+	
+	*out = f->outbuf;
+	*outlen = o - f->outbuf;
+	*outprespace = f->outpre;
+	
+}
+
+static void
+filter(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
+{
+	filter_run(f, in, len, prespace, out, outlen, outprespace, FALSE);
+}
+
+static void 
+complete(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
+{
+	filter_run(f, in, len, prespace, out, outlen, outprespace, TRUE);
+}
+
+static void
+reset (CamelMimeFilter *f)
+{
+	/* no-op */
+}
+
+CamelMimeFilter *
+camel_mime_filter_pgp_new(void)
+{
+	CamelMimeFilterPgp *pgpfilter = (CamelMimeFilterPgp *)camel_object_new (camel_mime_filter_pgp_get_type());
+
+	return (CamelMimeFilter *) pgpfilter;
+}
--- /dev/null	2005-06-24 17:28:39.844700400 +1200
+++ camel/camel-mime-filter-pgp.h	2005-05-29 22:12:25.000000000 +1200
@@ -0,0 +1,54 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005 Matt Brown..
+ *
+ * Authors: Matt Brown <matt mattb net nz>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CAMEL_MIME_FILTER_PGP_H
+#define _CAMEL_MIME_FILTER_PGP_H
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#include <camel/camel-mime-filter.h>
+
+#define CAMEL_MIME_FILTER_PGP_TYPE         (camel_mime_filter_canon_get_type ())
+#define CAMEL_MIME_FILTER_PGP(obj)         CAMEL_CHECK_CAST (obj, CAMEL_MIME_FILTER_PGP_TYPE, CamelMimeFilterPgp)
+#define CAMEL_MIME_FILTER_PGP_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, CAMEL_MIME_FILTER_PGP_TYPE, CamelMimeFilterPgpClass)
+#define CAMEL_IS_MIME_FILTER_PGP(obj)      CAMEL_CHECK_TYPE (obj, CAMEL_MIME_FILTER_PGP_TYPE)
+
+typedef struct _CamelMimeFilterPgp {
+	CamelMimeFilter filter;
+	int state;
+} CamelMimeFilterPgp;
+
+typedef struct _CamelMimeFilterPgpClass {
+	CamelMimeFilterClass parent_class;
+} CamelMimeFilterPgpClass;
+
+CamelType camel_mime_filter_pgp_get_type (void);
+
+CamelMimeFilter *camel_mime_filter_pgp_new(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ! _CAMEL_MIME_FILTER_PGP_H */
Index: mail/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/mail/ChangeLog,v
retrieving revision 1.3647
diff -u -p -r1.3647 ChangeLog
--- mail/ChangeLog	21 Jun 2005 05:33:47 -0000	1.3647
+++ mail/ChangeLog	24 Jun 2005 08:50:07 -0000
@@ -1,3 +1,11 @@
+2005-06-24	Matt Brown	<matt mattb net nz>
+
+	* em-inline-filter.c: implement extraction of inline signed/encrypted pgp
+	parts and package them into x-inlinepgp-signed/x-inline-pgp-encrypted
+	parts.
+	* em-format-html.c: Formatters to verify/decrypt and then display the
+	parts generated by the inline filter.
+	
 2005-06-21 Brian Mury <b mury ieee org>
 
 	** See bug #301466.
Index: mail/em-format-html.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format-html.c,v
retrieving revision 1.78
diff -u -p -r1.78 em-format-html.c
--- mail/em-format-html.c	19 May 2005 06:06:35 -0000	1.78
+++ mail/em-format-html.c	24 Jun 2005 08:50:13 -0000
@@ -48,6 +48,9 @@
 #include <camel/camel-mime-filter.h>
 #include <camel/camel-mime-filter-tohtml.h>
 #include <camel/camel-mime-filter-enriched.h>
+#include <camel/camel-mime-filter-pgp.h>
+#include <camel/camel-mime-filter-basic.h>
+#include <camel/camel-gpg-context.h>
 #include <camel/camel-cipher-context.h>
 #include <camel/camel-multipart.h>
 #include <camel/camel-stream-mem.h>
@@ -644,6 +647,117 @@ efh_format_secure(EMFormat *emf, CamelSt
 }
 
 static void
+efh_inlinepgp_signed(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
+{
+	
+	CamelCipherContext *cipher;
+	CamelCipherValidity *valid;
+	CamelException *ex;
+	CamelMimePart *opart=NULL;
+	CamelContentType *type;
+	CamelStreamFilter *filtered_stream;
+	CamelStream *ostream;
+	CamelDataWrapper *dw;
+	CamelMimeFilterPgp *pgp_filter;
+
+	/* Check we're passed valid input */
+	type = camel_mime_part_get_content_type(ipart);
+	if (!camel_content_type_is(type, "application", "x-inlinepgp-signed")) {
+		em_format_format_error((EMFormat *)efh, stream, 
+				"Invalid mime type passed to inline PGP format");
+		return;
+	}
+
+	ex = camel_exception_new();
+	cipher = camel_gpg_context_new (((EMFormat *)efh)->session);
+	/* Verify the signature of the message */
+	valid = camel_cipher_verify(cipher, ipart, ex);
+	if (!valid) {
+		/* Display an error */
+		em_format_format_error((EMFormat *)efh, stream, ex->desc ? ex->desc : 
+				_("Unknown error verifying signed messaage"));
+		camel_exception_free(ex);
+		camel_object_unref(cipher);
+		return;
+    	}
+        
+	/* Setup output stream */
+	ostream = camel_stream_mem_new();
+	filtered_stream = camel_stream_filter_new_with_stream(ostream);
+
+	/* Add PGP header / footer filter */
+	pgp_filter = (CamelMimeFilterPgp *)camel_mime_filter_pgp_new();
+	camel_stream_filter_add(filtered_stream, (CamelMimeFilter *)pgp_filter);
+	camel_object_unref(pgp_filter);
+	
+	/* Pass through the filters that have been setup */
+	dw = camel_medium_get_content_object((CamelMedium *)ipart);
+	camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filtered_stream);
+	camel_stream_flush((CamelStream *)filtered_stream);
+	camel_object_unref(filtered_stream);
+	
+	/* Extract new part and display it as text/plain */ 
+	dw = camel_data_wrapper_new();
+	camel_data_wrapper_construct_from_stream(dw, ostream);
+	camel_data_wrapper_set_mime_type(dw, "text/plain");
+	opart = camel_mime_part_new();
+	camel_medium_set_content_object((CamelMedium *)opart, dw);
+	camel_mime_part_set_content_type(opart, "text/plain");
+	
+	/* Pass it off to the real formatter */	
+	em_format_format_secure((EMFormat *)efh, stream, opart, valid);
+
+	/* Clean Up */
+	camel_object_unref(dw);
+	camel_object_unref(opart);
+	camel_object_unref(ostream);
+	camel_object_unref(cipher);
+	camel_exception_free(ex);	
+}
+
+static void
+efh_inlinepgp_encrypted(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
+{	
+	CamelCipherContext *cipher;
+	CamelCipherValidity *valid;
+	CamelException *ex;
+	CamelMimePart *opart;
+	CamelContentType *type;
+    
+	/* Check we're passed valid input */
+	type = camel_mime_part_get_content_type(ipart);
+	if (!camel_content_type_is(type, "application", "x-inlinepgp-encrypted")) {
+		em_format_format_error((EMFormat *)efh, stream, 
+				"Invalid mime type passed to inline PGP format encrypted");
+		return;
+	}
+	
+	cipher = camel_gpg_context_new (((EMFormat *)efh)->session);
+	ex = camel_exception_new();
+	opart = camel_mime_part_new();
+	/* Decrypt the message */
+	valid = camel_cipher_decrypt (cipher, ipart, opart, ex);	
+	if (!valid) {
+		/* Display an error */
+		em_format_format_error((EMFormat *)efh, stream, ex->desc ? ex->desc : 
+				_("Unknown error decrypting messaage"));
+		camel_exception_free(ex);
+		camel_object_unref(cipher);
+		camel_object_unref(opart);
+		return;
+	}
+
+	/* Pass it off to the real formatter */	
+	em_format_format_secure((EMFormat *)efh, stream, opart, valid);
+
+	/* Clean Up */
+	camel_object_unref(opart);
+	camel_object_unref (cipher);
+	camel_exception_free (ex);
+}
+
+	
+static void
 efh_text_plain(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
 {
 	CamelStreamFilter *filtered_stream;
@@ -1099,6 +1212,8 @@ static EMFormatHandler type_builtin_tabl
 	{ "message/external-body", (EMFormatFunc)efh_message_external },
 	{ "message/delivery-status", (EMFormatFunc)efh_message_deliverystatus },
 	{ "multipart/related", (EMFormatFunc)efh_multipart_related },
+	{ "application/x-inlinepgp-signed", (EMFormatFunc)efh_inlinepgp_signed },
+	{ "application/x-inlinepgp-encrypted", (EMFormatFunc)efh_inlinepgp_encrypted },
 
 	/* This is where one adds those busted, non-registered types,
 	   that some idiot mailer writers out there decide to pull out
Index: mail/em-format.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format.c,v
retrieving revision 1.47
diff -u -p -r1.47 em-format.c
--- mail/em-format.c	19 May 2005 06:06:35 -0000	1.47
+++ mail/em-format.c	24 Jun 2005 08:50:17 -0000
@@ -914,6 +915,8 @@ int em_format_is_attachment(EMFormat *em
 	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-inlinepgp-signed")
+		 || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-encrypted")	 
 		 || (camel_content_type_is (dw->mime_type, "text", "*")
 		     && camel_mime_part_get_filename(part) == NULL));
 }
Index: mail/em-inline-filter.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-inline-filter.c,v
retrieving revision 1.8
diff -u -p -r1.8 em-inline-filter.c
--- mail/em-inline-filter.c	28 Feb 2005 04:51:26 -0000	1.8
+++ mail/em-inline-filter.c	24 Jun 2005 08:50:18 -0000
@@ -102,6 +102,7 @@ enum {
 	EMIF_BINHEX,
 	EMIF_POSTSCRIPT,
 	EMIF_PGPSIGNED,
+	EMIF_PGPENCRYPTED,
 };
 const struct {
 	const char *name;
@@ -112,7 +113,8 @@ const struct {
 	{ "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-inlinepgp-signed", CAMEL_TRANSFER_ENCODING_DEFAULT, },
+	{ "application/x-inlinepgp-encrypted", CAMEL_TRANSFER_ENCODING_DEFAULT, },	
 };
 
 static void
@@ -124,12 +126,16 @@ emif_add_part(EMInlineFilter *emif, cons
 	CamelMimePart *part;
 	const char *mimetype;
 
-	if (emif->state == EMIF_PLAIN)
+	if (emif->state == EMIF_PLAIN || emif->state == EMIF_PGPSIGNED || emif->state == EMIF_PGPENCRYPTED)
 		type = emif->base_encoding;
 	else
 		type = emif_types[emif->state].type;
 
 	g_byte_array_append(emif->data, data, len);
+	/* check the part will actually have content */
+	if (emif->data->len <= 0) {
+		return;
+	}
 	mem = camel_stream_mem_new_with_byte_array(emif->data);
 	emif->data = g_byte_array_new();
 
@@ -223,17 +229,18 @@ emif_scan(CamelMimeFilter *f, char *in, 
 				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
+			} else if (strncmp(start, "-----BEGIN PGP MESSAGE-----", 27) == 0) {
+				inptr[-1] = '\n';
+				emif_add_part(emif, data_start, start-data_start);
+				data_start = start;
+				emif->state = EMIF_PGPENCRYPTED;
 			}
+
 			break;
 		case EMIF_UUENC:
 			if (strcmp(start, "end") == 0) {
@@ -279,7 +286,6 @@ emif_scan(CamelMimeFilter *f, char *in, 
 			}
 			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);
@@ -287,6 +293,14 @@ emif_scan(CamelMimeFilter *f, char *in, 
 				emif->state = EMIF_PLAIN;
 			}
 			break;
+		case EMIF_PGPENCRYPTED:
+			if (strcmp(start, "-----END PGP MESSAGE-----") == 0) {
+				inptr[-1] = '\n';
+				emif_add_part(emif, data_start, inptr-data_start);
+				data_start = inptr;
+				emif->state = EMIF_PLAIN;
+			}
+			break;
 		}
 
 		inptr[-1] = '\n';
Index: mail/em-format-html.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format-html.c,v
retrieving revision 1.78
diff -u -r1.78 em-format-html.c
--- mail/em-format-html.c	19 May 2005 06:06:35 -0000	1.78
+++ mail/em-format-html.c	15 Jun 2005 12:14:16 -0000
@@ -656,10 +771,6 @@
 	int i, count, len;
 	struct _EMFormatHTMLCache *efhc;
 
-	camel_stream_printf (stream,
-			     "<div style=\"border: solid #%06x 1px; background-color: #%06x; padding: 10px;\">\n",
-			     efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
-
 	flags = efh->text_html_flags;
 	
 	dw = camel_medium_get_content_object((CamelMedium *)part);
@@ -727,10 +838,14 @@
 
 		type = camel_mime_part_get_content_type(newpart);
 		if (camel_content_type_is (type, "text", "*")) {
+			camel_stream_printf (stream,
+   					"<div style=\"border: solid #%06x 1px; background-color: #%06x; padding: 10px;\">\n",
+   					efh->frame_colour & 0xffffff, efh->content_colour & 0xffffff);
 			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");
+			camel_stream_write_string(stream, "</div>\n");
 		} else {
 			g_string_append_printf(((EMFormat *)efh)->part_id, ".inline.%d", i);
 			em_format_part((EMFormat *)efh, stream, newpart);
@@ -739,7 +854,6 @@
 	}
 
 	camel_object_unref(filtered_stream);
-	camel_stream_write_string(stream, "</div>\n");
 }
 
 static void


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