[gmime] Added new GMimeFilterOpenPGP filter



commit 61271a33efe33ca7d0cd29d889da662b2dbaeb99
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Tue Dec 12 17:30:45 2017 -0500

    Added new GMimeFilterOpenPGP filter

 docs/reference/gmime-docs.sgml    |    2 +
 docs/reference/gmime-sections.txt |   25 +++-
 docs/reference/gmime.hierarchy    |    1 +
 gmime/Makefile.am                 |    2 +
 gmime/gmime-filter-openpgp.c      |  412 +++++++++++++++++++++++++++++++++++++
 gmime/gmime-filter-openpgp.h      |  130 ++++++++++++
 gmime/gmime-parser.c              |   56 ++---
 gmime/gmime-part.h                |   15 +--
 gmime/gmime.h                     |    1 +
 tests/test-pgp.c                  |   59 ++++++
 10 files changed, 655 insertions(+), 48 deletions(-)
---
diff --git a/docs/reference/gmime-docs.sgml b/docs/reference/gmime-docs.sgml
index 890d68e..8626d9f 100644
--- a/docs/reference/gmime-docs.sgml
+++ b/docs/reference/gmime-docs.sgml
@@ -52,6 +52,7 @@
 <!ENTITY GMimeFilterFrom SYSTEM "xml/gmime-filter-from.xml">
 <!ENTITY GMimeFilterGZip SYSTEM "xml/gmime-filter-gzip.xml">
 <!ENTITY GMimeFilterHTML SYSTEM "xml/gmime-filter-html.xml">
+<!ENTITY GMimeFilterOpenPGP SYSTEM "xml/gmime-filter-openpgp.xml">
 <!ENTITY GMimeFilterSmtpData SYSTEM "xml/gmime-filter-smtp-data.xml">
 <!ENTITY GMimeFilterStrip SYSTEM "xml/gmime-filter-strip.xml">
 <!ENTITY GMimeFilterUnix2Dos SYSTEM "xml/gmime-filter-unix2dos.xml">
@@ -218,6 +219,7 @@ string utilities, file utilities, a main loop abstraction, and so on.
       &GMimeFilterFrom;
       &GMimeFilterGZip;
       &GMimeFilterHTML;
+      &GMimeFilterOpenPGP;
       &GMimeFilterSmtpData;
       &GMimeFilterStrip;
       &GMimeFilterUnix2Dos;
diff --git a/docs/reference/gmime-sections.txt b/docs/reference/gmime-sections.txt
index 796dff8..acffe1d 100644
--- a/docs/reference/gmime-sections.txt
+++ b/docs/reference/gmime-sections.txt
@@ -492,6 +492,30 @@ GMIME_FILTER_CHECKSUM_GET_CLASS
 </SECTION>
 
 <SECTION>
+<FILE>gmime-filter-openpgp</FILE>
+GMimeOpenPGPData
+GMimeOpenPGPState
+GMimeOpenPGPMarker
+GMimeFilterOpenPGP
+g_mime_filter_openpgp_new
+g_mime_filter_openpgp_get_data_type
+g_mime_filter_openpgp_get_begin_offset
+g_mime_filter_openpgp_get_enbd_offset
+
+<SUBSECTION Private>
+g_mime_filter_openpgp_get_type
+
+<SUBSECTION Standard>
+GMimeFilterOpenPGPClass
+GMIME_TYPE_FILTER_OPENPGP
+GMIME_FILTER_OPENPGP
+GMIME_IS_FILTER_OPENPGP
+GMIME_FILTER_OPENPGP_CLASS
+GMIME_IS_FILTER_OPENPGP_CLASS
+GMIME_FILTER_OPENPGP_GET_CLASS
+</SECTION>
+
+<SECTION>
 <FILE>gmime-filter-strip</FILE>
 GMimeFilterStrip
 g_mime_filter_strip_new
@@ -811,7 +835,6 @@ GMimeObjectClass
 <SECTION>
 <FILE>gmime-part</FILE>
 GMimePart
-GMimeOpenPGPData
 g_mime_part_new
 g_mime_part_new_with_type
 g_mime_part_is_attachment
diff --git a/docs/reference/gmime.hierarchy b/docs/reference/gmime.hierarchy
index e29d056..9aea60b 100644
--- a/docs/reference/gmime.hierarchy
+++ b/docs/reference/gmime.hierarchy
@@ -38,6 +38,7 @@ GObject
     GMimeFilterFrom
     GMimeFilterGZip
     GMimeFilterHTML
+    GMimeFilterOpenPGP
     GMimeFilterSmtpData
     GMimeFilterStrip
     GMimeFilterUnix2Dos
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index 10fa06d..b90dc4b 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -42,6 +42,7 @@ libgmime_3_0_la_SOURCES =             \
        gmime-filter-from.c             \
        gmime-filter-gzip.c             \
        gmime-filter-html.c             \
+       gmime-filter-openpgp.c          \
        gmime-filter-smtp-data.c        \
        gmime-filter-strip.c            \
        gmime-filter-unix2dos.c         \
@@ -106,6 +107,7 @@ gmimeinclude_HEADERS =                      \
        gmime-filter-from.h             \
        gmime-filter-gzip.h             \
        gmime-filter-html.h             \
+       gmime-filter-openpgp.h          \
        gmime-filter-smtp-data.h        \
        gmime-filter-strip.h            \
        gmime-filter-unix2dos.h         \
diff --git a/gmime/gmime-filter-openpgp.c b/gmime/gmime-filter-openpgp.c
new file mode 100644
index 0000000..d335bcc
--- /dev/null
+++ b/gmime/gmime-filter-openpgp.c
@@ -0,0 +1,412 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*  GMime
+ *  Copyright (C) 2000-2017 Jeffrey Stedfast
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gmime-filter-openpgp.h"
+
+
+/**
+ * SECTION: gmime-filter-openpgp
+ * @title: GMimeFilterOpenPGP
+ * @short_description: Detect OpenPGP markers.
+ *
+ * A #GMimeFilter for detecting OpenPGP markers and filtering out any content outside the bounds of said 
markers.
+ **/
+
+/* Note: if you add/remove markers, update GMimeParser as well */
+const GMimeOpenPGPMarker g_mime_openpgp_markers[9] = {
+       { "-----BEGIN PGP MESSAGE-----",           27, GMIME_OPENPGP_NONE,                        
GMIME_OPENPGP_BEGIN_PGP_MESSAGE,           FALSE },
+       { "-----END PGP MESSAGE-----",             25, GMIME_OPENPGP_BEGIN_PGP_MESSAGE,           
GMIME_OPENPGP_END_PGP_MESSAGE,             TRUE  },
+       { "-----BEGIN PGP SIGNED MESSAGE-----",    34, GMIME_OPENPGP_NONE,                        
GMIME_OPENPGP_BEGIN_PGP_SIGNED_MESSAGE,    FALSE },
+       { "-----BEGIN PGP SIGNATURE-----",         29, GMIME_OPENPGP_BEGIN_PGP_SIGNED_MESSAGE,    
GMIME_OPENPGP_BEGIN_PGP_SIGNATURE,         FALSE },
+       { "-----END PGP SIGNATURE-----",           27, GMIME_OPENPGP_BEGIN_PGP_SIGNATURE,         
GMIME_OPENPGP_END_PGP_SIGNATURE,           TRUE  },
+       { "-----BEGIN PGP PUBLIC KEY BLOCK-----",  36, GMIME_OPENPGP_NONE,                        
GMIME_OPENPGP_BEGIN_PGP_PUBLIC_KEY_BLOCK,  FALSE },
+       { "-----END PGP PUBLIC KEY BLOCK-----",    34, GMIME_OPENPGP_BEGIN_PGP_PUBLIC_KEY_BLOCK,  
GMIME_OPENPGP_END_PGP_PUBLIC_KEY_BLOCK,    TRUE  },
+       { "-----BEGIN PGP PRIVATE KEY BLOCK-----", 37, GMIME_OPENPGP_NONE,                        
GMIME_OPENPGP_BEGIN_PGP_PRIVATE_KEY_BLOCK, FALSE },
+       { "-----END PGP PRIVATE KEY BLOCK-----",   35, GMIME_OPENPGP_BEGIN_PGP_PRIVATE_KEY_BLOCK, 
GMIME_OPENPGP_END_PGP_PRIVATE_KEY_BLOCK,   TRUE  }
+};
+
+static void g_mime_filter_openpgp_class_init (GMimeFilterOpenPGPClass *klass);
+static void g_mime_filter_openpgp_init (GMimeFilterOpenPGP *filter, GMimeFilterOpenPGPClass *klass);
+
+static GMimeFilter *filter_copy (GMimeFilter *filter);
+static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
+                          char **out, size_t *outlen, size_t *outprespace);
+static void filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
+                            char **out, size_t *outlen, size_t *outprespace);
+static void filter_reset (GMimeFilter *filter);
+
+
+static GMimeFilterClass *parent_class = NULL;
+
+
+GType
+g_mime_filter_openpgp_get_type (void)
+{
+       static GType type = 0;
+       
+       if (!type) {
+               static const GTypeInfo info = {
+                       sizeof (GMimeFilterOpenPGPClass),
+                       NULL, /* base_class_init */
+                       NULL, /* base_class_finalize */
+                       (GClassInitFunc) g_mime_filter_openpgp_class_init,
+                       NULL, /* class_finalize */
+                       NULL, /* class_data */
+                       sizeof (GMimeFilterOpenPGP),
+                       0,    /* n_preallocs */
+                       (GInstanceInitFunc) g_mime_filter_openpgp_init,
+               };
+               
+               type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterOpenPGP", &info, 0);
+       }
+       
+       return type;
+}
+
+
+static void
+g_mime_filter_openpgp_class_init (GMimeFilterOpenPGPClass *klass)
+{
+       GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
+       
+       parent_class = g_type_class_ref (GMIME_TYPE_FILTER);
+       
+       filter_class->copy = filter_copy;
+       filter_class->filter = filter_filter;
+       filter_class->complete = filter_complete;
+       filter_class->reset = filter_reset;
+}
+
+static void
+g_mime_filter_openpgp_init (GMimeFilterOpenPGP *filter, GMimeFilterOpenPGPClass *klass)
+{
+       filter->state = GMIME_OPENPGP_NONE;
+       filter->seen_end_marker = FALSE;
+       filter->midline = FALSE;
+       filter->begin_offset = -1;
+       filter->end_offset = -1;
+       filter->position = 0;
+       filter->next = 0;
+}
+
+
+static GMimeFilter *
+filter_copy (GMimeFilter *filter)
+{
+       return g_mime_filter_openpgp_new ();
+}
+
+static gboolean
+is_marker (const char *input, const char *inend, const GMimeOpenPGPMarker *marker, gboolean *cr)
+{
+       const char *markerend = marker->marker + marker->len;
+       const char *markerptr = marker->marker;
+       const char *inptr = input;
+       
+       *cr = FALSE;
+       
+       while (inptr < inend && markerptr < markerend) {
+               if (*inptr != *markerptr)
+                       return FALSE;
+               
+               markerptr++;
+               inptr++;
+       }
+       
+       if (markerptr < markerend)
+               return FALSE;
+       
+       if (inptr < inend && *inptr == '\r') {
+               *cr = TRUE;
+               inptr++;
+       }
+       
+       return *inptr == '\n';
+}
+
+static gboolean
+is_partial_match (const char *input, const char *inend, const GMimeOpenPGPMarker *marker)
+{
+       const char *markerend = marker->marker + marker->len;
+       const char *markerptr = marker->marker;
+       const char *inptr = input;
+       
+       while (inptr < inend && markerptr < markerend) {
+               if (*inptr != *markerptr)
+                       return FALSE;
+               
+               markerptr++;
+               inptr++;
+       }
+       
+       if (markerptr < markerend)
+               return FALSE;
+       
+       if (inptr < inend && *inptr == '\r')
+               inptr++;
+       
+       return inptr == inend;
+}
+
+static void
+set_position (GMimeFilterOpenPGP *openpgp, gint64 offset, guint marker, gboolean cr)
+{
+       size_t length = g_mime_openpgp_markers[marker].len + (cr ? 2 : 1);
+       
+       switch (openpgp->state) {
+       case GMIME_OPENPGP_BEGIN_PGP_PRIVATE_KEY_BLOCK: openpgp->begin_offset = openpgp->position + offset; 
break;
+       case GMIME_OPENPGP_END_PGP_PRIVATE_KEY_BLOCK: openpgp->end_offset = openpgp->position + offset + 
length; break;
+       case GMIME_OPENPGP_BEGIN_PGP_PUBLIC_KEY_BLOCK: openpgp->begin_offset = openpgp->position + offset; 
break;
+       case GMIME_OPENPGP_END_PGP_PUBLIC_KEY_BLOCK: openpgp->end_offset = openpgp->position + offset + 
length; break;
+       case GMIME_OPENPGP_BEGIN_PGP_SIGNED_MESSAGE: openpgp->begin_offset = openpgp->position + offset; 
break;
+       case GMIME_OPENPGP_END_PGP_SIGNATURE: openpgp->end_offset = openpgp->position + offset + length; 
break;
+       case GMIME_OPENPGP_BEGIN_PGP_MESSAGE: openpgp->begin_offset = openpgp->position + offset; break;
+       case GMIME_OPENPGP_END_PGP_MESSAGE: openpgp->end_offset = openpgp->position + offset + length; break;
+       default: break;
+       }
+}
+
+static void
+scan (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+      char **outbuf, size_t *outlen, size_t *outprespace, gboolean flush)
+{
+       GMimeFilterOpenPGP *openpgp = (GMimeFilterOpenPGP *) filter;
+       const char *inend = inbuf + inlen;
+       const char *inptr = inbuf;
+       gboolean cr;
+       guint i;
+       
+       *outprespace = prespace;
+       *outbuf = inbuf;
+       *outlen = 0;
+       
+       if (openpgp->seen_end_marker || inlen == 0)
+               return;
+       
+       if (openpgp->midline) {
+               while (inptr < inend && *inptr != '\n')
+                       inptr++;
+               
+               if (inptr == inend) {
+                       if (openpgp->state != GMIME_OPENPGP_NONE)
+                               *outlen = inlen;
+                       
+                       openpgp->position += inlen;
+                       return;
+               }
+               
+               openpgp->midline = FALSE;
+       }
+       
+       if (openpgp->state == GMIME_OPENPGP_NONE) {
+               do {
+                       const char *lineptr = inptr;
+                       
+                       while (inptr < inend && *inptr != '\n')
+                               inptr++;
+                       
+                       if (inptr == inend) {
+                               gboolean partial = FALSE;
+                               
+                               for (i = 0; i < G_N_ELEMENTS (g_mime_openpgp_markers); i++) {
+                                       if (g_mime_openpgp_markers[i].before == openpgp->state && 
is_partial_match (lineptr, inend, &g_mime_openpgp_markers[i])) {
+                                               partial = TRUE;
+                                               break;
+                                       }
+                               }
+                               
+                               if (partial) {
+                                       g_mime_filter_backup (filter, lineptr, inptr - lineptr);
+                                       openpgp->position += lineptr - inbuf;
+                               } else {
+                                       openpgp->position += inptr - lineptr;
+                                       openpgp->midline = TRUE;
+                               }
+                               
+                               return;
+                       }
+                       
+                       inptr++;
+                       
+                       for (i = 0; i < G_N_ELEMENTS (g_mime_openpgp_markers); i++) {
+                               if (g_mime_openpgp_markers[i].before == openpgp->state && is_marker (lineptr, 
inend, &g_mime_openpgp_markers[i], &cr)) {
+                                       openpgp->state = g_mime_openpgp_markers[i].after;
+                                       set_position (openpgp, lineptr - inbuf, i, cr);
+                                       *outbuf = (char *) lineptr;
+                                       *outlen = inptr - lineptr;
+                                       openpgp->next = i + 1;
+                                       break;
+                               }
+                       }
+               } while (inptr < inend && openpgp->state == GMIME_OPENPGP_NONE);
+               
+               if (inptr == inend) {
+                       openpgp->position += inptr - inbuf;
+                       return;
+               }
+       }
+
+       do {
+               const char *lineptr = inptr;
+               
+               while (inptr < inend && *inptr != '\n')
+                       inptr++;
+               
+               if (inptr == inend) {
+                       if (!flush) {
+                               if (is_partial_match (lineptr, inend, 
&g_mime_openpgp_markers[openpgp->next])) {
+                                       g_mime_filter_backup (filter, lineptr, inptr - lineptr);
+                                       openpgp->position += lineptr - inbuf;
+                                       *outlen = lineptr - *outbuf;
+                               } else {
+                                       openpgp->position += inptr - inbuf;
+                                       *outlen = inptr - *outbuf;
+                                       openpgp->midline = TRUE;
+                               }
+                               
+                               return;
+                       }
+                       
+                       openpgp->position += inptr - inbuf;
+                       *outlen = inptr - *outbuf;
+                       
+                       return;
+               }
+               
+               inptr++;
+               
+               if (is_marker (lineptr, inend, &g_mime_openpgp_markers[openpgp->next], &cr)) {
+                       openpgp->seen_end_marker = g_mime_openpgp_markers[openpgp->next].is_end_marker;
+                       openpgp->state = g_mime_openpgp_markers[openpgp->next].after;
+                       set_position (openpgp, lineptr - inbuf, openpgp->next, cr);
+                       openpgp->next++;
+                       
+                       if (openpgp->seen_end_marker)
+                               break;
+               }
+       } while (inptr < inend);
+       
+       openpgp->position += inptr - inbuf;
+       *outlen = inptr - *outbuf;
+}
+
+static void
+filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+              char **outbuf, size_t *outlen, size_t *outprespace)
+{
+       scan (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace, FALSE);
+}
+
+static void 
+filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+                char **outbuf, size_t *outlen, size_t *outprespace)
+{
+       scan (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace, TRUE);
+}
+
+static void
+filter_reset (GMimeFilter *filter)
+{
+       GMimeFilterOpenPGP *openpgp = (GMimeFilterOpenPGP *) filter;
+       
+       openpgp->state = GMIME_OPENPGP_NONE;
+       openpgp->seen_end_marker = FALSE;
+       openpgp->midline = FALSE;
+       openpgp->begin_offset = -1;
+       openpgp->end_offset = -1;
+       openpgp->position = 0;
+       openpgp->next = 0;
+}
+
+
+/**
+ * g_mime_filter_openpgp_new:
+ *
+ * Creates a new #GMimeFilterOpenPGP filter.
+ *
+ * Returns: a new #GMimeFilterOpenPGP filter.
+ **/
+GMimeFilter *
+g_mime_filter_openpgp_new (void)
+{
+       return (GMimeFilter *) g_object_new (GMIME_TYPE_FILTER_OPENPGP, NULL);
+}
+
+
+/**
+ * g_mime_filter_openpgp_get_data_type:
+ * @openpgp: A #GMimeFilterOpenPGP filter
+ *
+ * Gets the type of OpenPGP data that has been detected.
+ *
+ * Returns: a #GMimeOpenPGPData value.
+ **/
+GMimeOpenPGPData
+g_mime_filter_openpgp_get_data_type (GMimeFilterOpenPGP *openpgp)
+{
+       g_return_val_if_fail (GMIME_IS_FILTER_OPENPGP (openpgp), GMIME_OPENPGP_DATA_NONE);
+       
+       switch (openpgp->state) {
+       case GMIME_OPENPGP_END_PGP_PRIVATE_KEY_BLOCK: return GMIME_OPENPGP_DATA_PRIVATE_KEY;
+       case GMIME_OPENPGP_END_PGP_PUBLIC_KEY_BLOCK: return GMIME_OPENPGP_DATA_PUBLIC_KEY;
+       case GMIME_OPENPGP_END_PGP_SIGNATURE: return GMIME_OPENPGP_DATA_SIGNED;
+       case GMIME_OPENPGP_END_PGP_MESSAGE: return GMIME_OPENPGP_DATA_ENCRYPTED;
+       default: return GMIME_OPENPGP_DATA_NONE;
+       }
+}
+
+
+/**
+ * g_mime_filter_openpgp_get_begin_offset:
+ * @openpgp: A #GMimeFilterOpenPGP filter
+ *
+ * Gets the stream offset of the beginning of the OpenPGP data block, if any have been found.
+ *
+ * Returns: The stream offset or %-1 if no OpenPGP block was found.
+ **/
+gint64
+g_mime_filter_openpgp_get_begin_offset (GMimeFilterOpenPGP *openpgp)
+{
+       g_return_val_if_fail (GMIME_IS_FILTER_OPENPGP (openpgp), -1);
+       
+       return openpgp->begin_offset;
+}
+
+
+/**
+ * g_mime_filter_openpgp_get_end_offset:
+ * @openpgp: A #GMimeFilterOpenPGP filter
+ *
+ * Gets the stream offset of the end of the OpenPGP data block, if any have been found.
+ *
+ * Returns: The stream offset or %-1 if no OpenPGP block was found.
+ **/
+gint64
+g_mime_filter_openpgp_get_end_offset (GMimeFilterOpenPGP *openpgp)
+{
+       g_return_val_if_fail (GMIME_IS_FILTER_OPENPGP (openpgp), -1);
+       
+       return openpgp->end_offset;
+}
diff --git a/gmime/gmime-filter-openpgp.h b/gmime/gmime-filter-openpgp.h
new file mode 100644
index 0000000..accdac2
--- /dev/null
+++ b/gmime/gmime-filter-openpgp.h
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*  GMime
+ *  Copyright (C) 2000-2017 Jeffrey Stedfast
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#ifndef __GMIME_FILTER_OPENPGP_H__
+#define __GMIME_FILTER_OPENPGP_H__
+
+#include <gmime/gmime-filter.h>
+
+G_BEGIN_DECLS
+
+#define GMIME_TYPE_FILTER_OPENPGP            (g_mime_filter_openpgp_get_type ())
+#define GMIME_FILTER_OPENPGP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMIME_TYPE_FILTER_OPENPGP, 
GMimeFilterOpenPGP))
+#define GMIME_FILTER_OPENPGP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GMIME_TYPE_FILTER_OPENPGP, 
GMimeFilterOpenPGPClass))
+#define GMIME_IS_FILTER_OPENPGP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GMIME_TYPE_FILTER_OPENPGP))
+#define GMIME_IS_FILTER_OPENPGP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GMIME_TYPE_FILTER_OPENPGP))
+#define GMIME_FILTER_OPENPGP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GMIME_TYPE_FILTER_OPENPGP, 
GMimeFilterOpenPGPClass))
+
+typedef struct _GMimeFilterOpenPGP GMimeFilterOpenPGP;
+typedef struct _GMimeFilterOpenPGPClass GMimeFilterOpenPGPClass;
+
+
+/**
+ * GMimeOpenPGPData:
+ * @GMIME_OPENPGP_DATA_NONE: No OpenPGP data found.
+ * @GMIME_OPENPGP_DATA_ENCRYPTED: The content contains OpenPGP encrypted data.
+ * @GMIME_OPENPGP_DATA_SIGNED: The content contains OpenPGP signed data.
+ * @GMIME_OPENPGP_DATA_PUBLIC_KEY: The content contains OpenPGP public key data.
+ * @GMIME_OPENPGP_DATA_PRIVATE_KEY: The content contains OpenPGP private key data.
+ *
+ * The type of OpenPGP data found, if any.
+ **/
+typedef enum {
+       GMIME_OPENPGP_DATA_NONE,
+       GMIME_OPENPGP_DATA_ENCRYPTED,
+       GMIME_OPENPGP_DATA_SIGNED,
+       GMIME_OPENPGP_DATA_PUBLIC_KEY,
+       GMIME_OPENPGP_DATA_PRIVATE_KEY
+} GMimeOpenPGPData;
+
+
+/**
+ * GMimeOpenPGPState:
+ * @GMIME_OPENPGP_NONE: No OpenPGP markers have been found (yet).
+ * @GMIME_OPENPGP_BEGIN_PGP_MESSAGE: The "-----BEGIN PGP MESSAGE-----" marker has been found.
+ * @GMIME_OPENPGP_END_PGP_MESSAGE: The "-----END PGP MESSAGE-----" marker has been found.
+ * @GMIME_OPENPGP_BEGIN_PGP_SIGNED_MESSAGE: The "-----BEGIN PGP SIGNED MESSAGE-----" marker has been found.
+ * @GMIME_OPENPGP_BEGIN_PGP_SIGNATURE: The "-----BEGIN PGP SIGNATURE-----" marker has been found.
+ * @GMIME_OPENPGP_END_PGP_SIGNATURE: The "-----END PGP SIGNATURE-----" marker has been found.
+ * @GMIME_OPENPGP_BEGIN_PGP_PUBLIC_KEY_BLOCK: The "-----BEGIN PGP PUBLIC KEY BLOCK-----" marker has been 
found.
+ * @GMIME_OPENPGP_END_PGP_PUBLIC_KEY_BLOCK: The "-----END PGP PUBLIC KEY BLOCK-----" marker has been found.
+ * @GMIME_OPENPGP_BEGIN_PGP_PRIVATE_KEY_BLOCK: The "-----BEGIN PGP PRIVATE KEY BLOCK-----" marker has been 
found.
+ * @GMIME_OPENPGP_END_PGP_PRIVATE_KEY_BLOCK: The "-----END PGP PRIVATE KEY BLOCK-----" marker has been found.
+ *
+ * The current state of the #GMimeFilterOpenPGP filter.
+ **/
+typedef enum {
+       GMIME_OPENPGP_NONE                        = 0,
+       GMIME_OPENPGP_BEGIN_PGP_MESSAGE           = (1 << 0),
+       GMIME_OPENPGP_END_PGP_MESSAGE             = (1 << 1) | (1 << 0),
+       GMIME_OPENPGP_BEGIN_PGP_SIGNED_MESSAGE    = (1 << 2),
+       GMIME_OPENPGP_BEGIN_PGP_SIGNATURE         = (1 << 3) | (1 << 2),
+       GMIME_OPENPGP_END_PGP_SIGNATURE           = (1 << 4) | (1 << 3) | (1 << 2),
+       GMIME_OPENPGP_BEGIN_PGP_PUBLIC_KEY_BLOCK  = (1 << 5),
+       GMIME_OPENPGP_END_PGP_PUBLIC_KEY_BLOCK    = (1 << 6) | (1 << 5),
+       GMIME_OPENPGP_BEGIN_PGP_PRIVATE_KEY_BLOCK = (1 << 7),
+       GMIME_OPENPGP_END_PGP_PRIVATE_KEY_BLOCK   = (1 << 8) | (1 << 7)
+} GMimeOpenPGPState;
+
+typedef struct {
+       const char *marker;
+       size_t len;
+       GMimeOpenPGPState before;
+       GMimeOpenPGPState after;
+       gboolean is_end_marker;
+} GMimeOpenPGPMarker;
+
+/**
+ * GMimeFilterOpenPGP:
+ * @parent_object: parent #GMimeFilter
+ *
+ * A filter to detect OpenPGP markers.
+ **/
+struct _GMimeFilterOpenPGP {
+       GMimeFilter parent_object;
+       
+       /* < private > */
+       GMimeOpenPGPState state;
+       gboolean seen_end_marker;
+       gboolean midline;
+       gint64 begin_offset;
+       gint64 end_offset;
+       gint64 position;
+       guint next;
+};
+
+struct _GMimeFilterOpenPGPClass {
+       GMimeFilterClass parent_class;
+       
+};
+
+
+GType g_mime_filter_openpgp_get_type (void);
+
+GMimeFilter *g_mime_filter_openpgp_new (void);
+
+GMimeOpenPGPData g_mime_filter_openpgp_get_data_type (GMimeFilterOpenPGP *openpgp);
+gint64 g_mime_filter_openpgp_get_begin_offset (GMimeFilterOpenPGP *openpgp);
+gint64 g_mime_filter_openpgp_get_end_offset (GMimeFilterOpenPGP *openpgp);
+
+G_END_DECLS
+
+#endif /* __GMIME_FILTER_OPENPGP_H__ */
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index 3cde304..7dbb0c1 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -59,29 +59,7 @@
  * into multiple #GMimeMessage objects.
  **/
 
-typedef enum {
-       OPENPGP_NONE                     = 0,
-       OPENPGP_BEGIN_PGP_MESSAGE        = (1 << 0),
-       OPENPGP_END_PGP_MESSAGE          = (1 << 1) | (1 << 0),
-       OPENPGP_BEGIN_PGP_SIGNED_MESSAGE = (1 << 2),
-       OPENPGP_BEGIN_PGP_SIGNATURE      = (1 << 3) | (1 << 2),
-       OPENPGP_END_PGP_SIGNATURE        = (1 << 4) | (1 << 3) | (1 << 2)
-} openpgp_state_t;
-
-typedef struct {
-       const char *marker;
-       size_t len;
-       openpgp_state_t before;
-       openpgp_state_t after;
-} GMimeOpenPGPMarker;
-
-static const GMimeOpenPGPMarker openpgp_markers[] = {
-       { "-----BEGIN PGP MESSAGE-----",        27, OPENPGP_NONE,                     
OPENPGP_BEGIN_PGP_MESSAGE },
-       { "-----END PGP MESSAGE-----",          25, OPENPGP_BEGIN_PGP_MESSAGE,        OPENPGP_END_PGP_MESSAGE 
  },
-       { "-----BEGIN PGP SIGNED MESSAGE-----", 34, OPENPGP_NONE,                     
OPENPGP_BEGIN_PGP_SIGNED_MESSAGE },
-       { "-----BEGIN PGP SIGNATURE-----",      29, OPENPGP_BEGIN_PGP_SIGNED_MESSAGE, 
OPENPGP_BEGIN_PGP_SIGNATURE },
-       { "-----END PGP SIGNATURE-----",        27, OPENPGP_BEGIN_PGP_SIGNATURE,      
OPENPGP_END_PGP_SIGNATURE }
-};
+extern const GMimeOpenPGPMarker g_mime_openpgp_markers[9];
 
 typedef enum {
        BOUNDARY_NONE,
@@ -188,7 +166,7 @@ struct _GMimeParserPrivate {
        
        BoundaryStack *bounds;
        
-       openpgp_state_t openpgp;
+       GMimeOpenPGPState openpgp;
        short int state;
        
        unsigned short int midline:1;
@@ -403,7 +381,7 @@ parser_init (GMimeParser *parser, GMimeStream *stream)
        
        priv->header_offset = -1;
        
-       priv->openpgp = OPENPGP_NONE;
+       priv->openpgp = GMIME_OPENPGP_NONE;
        
        priv->midline = FALSE;
        priv->seekable = offset != -1;
@@ -1414,13 +1392,13 @@ check_boundary (struct _GMimeParserPrivate *priv, const char *start, size_t len)
                len -= 2;
                
                /* check for OpenPGP markers... */
-               for (i = 0; i < G_N_ELEMENTS (openpgp_markers); i++) {
-                       const char *pgp_marker = openpgp_markers[i].marker + 2;
-                       openpgp_state_t state = openpgp_markers[i].before;
-                       size_t n = openpgp_markers[i].len - 2;
+               for (i = 0; i < G_N_ELEMENTS (g_mime_openpgp_markers); i++) {
+                       const char *pgp_marker = g_mime_openpgp_markers[i].marker + 2;
+                       GMimeOpenPGPState state = g_mime_openpgp_markers[i].before;
+                       size_t n = g_mime_openpgp_markers[i].len - 2;
                        
                        if (len == n && priv->openpgp == state && !strncmp (pgp_marker, start, len))
-                               priv->openpgp = openpgp_markers[i].after;
+                               priv->openpgp = g_mime_openpgp_markers[i].after;
                }
        }
        
@@ -1473,7 +1451,7 @@ parser_scan_content (GMimeParser *parser, GMimeStream *content, gboolean *empty)
        
        d(printf ("scan-content\n"));
        
-       priv->openpgp = OPENPGP_NONE;
+       priv->openpgp = GMIME_OPENPGP_NONE;
        priv->midline = FALSE;
        
        g_assert (priv->inptr <= priv->inend);
@@ -1619,10 +1597,22 @@ parser_scan_mime_part_content (GMimeParser *parser, GMimePart *mime_part, Bounda
        g_mime_part_set_content (mime_part, content);
        g_object_unref (content);
        
-       if (priv->openpgp == OPENPGP_END_PGP_SIGNATURE)
+       switch (priv->openpgp) {
+       case GMIME_OPENPGP_END_PGP_SIGNATURE:
                g_mime_part_set_openpgp_data (mime_part, GMIME_OPENPGP_DATA_SIGNED);
-       else if (priv->openpgp == OPENPGP_END_PGP_MESSAGE)
+               break;
+       case GMIME_OPENPGP_END_PGP_MESSAGE:
                g_mime_part_set_openpgp_data (mime_part, GMIME_OPENPGP_DATA_ENCRYPTED);
+               break;
+       case GMIME_OPENPGP_END_PGP_PUBLIC_KEY_BLOCK:
+               g_mime_part_set_openpgp_data (mime_part, GMIME_OPENPGP_DATA_PUBLIC_KEY);
+               break;
+       case GMIME_OPENPGP_END_PGP_PRIVATE_KEY_BLOCK:
+               g_mime_part_set_openpgp_data (mime_part, GMIME_OPENPGP_DATA_PRIVATE_KEY);
+               break;
+       default:
+               break;
+       }
 }
 
 static void
diff --git a/gmime/gmime-part.h b/gmime/gmime-part.h
index d2f720d..c5c1dfa 100644
--- a/gmime/gmime-part.h
+++ b/gmime/gmime-part.h
@@ -28,6 +28,7 @@
 #include <gmime/gmime-object.h>
 #include <gmime/gmime-encodings.h>
 #include <gmime/gmime-filter-best.h>
+#include <gmime/gmime-filter-openpgp.h>
 #include <gmime/gmime-data-wrapper.h>
 #include <gmime/gmime-crypto-context.h>
 
@@ -44,20 +45,6 @@ typedef struct _GMimePart GMimePart;
 typedef struct _GMimePartClass GMimePartClass;
 
 /**
- * GMimeOpenPGPData:
- * @GMIME_OPENPGP_DATA_NONE: The #GMimePart does not contain any OpenPGP data.
- * @GMIME_OPENPGP_DATA_ENCRYPTED: The #GMimePart contains OpenPGP encrypted data.
- * @GMIME_OPENPGP_DATA_SIGNED: The #GMimePart contains OpenPGP signed data.
- *
- * The type of OpenPGP data contained within the content of the #GMimePart, if any.
- **/
-typedef enum {
-       GMIME_OPENPGP_DATA_NONE,
-       GMIME_OPENPGP_DATA_ENCRYPTED,
-       GMIME_OPENPGP_DATA_SIGNED
-} GMimeOpenPGPData;
-
-/**
  * GMimePart:
  * @parent_object: parent #GMimeObject
  * @encoding: a #GMimeContentEncoding
diff --git a/gmime/gmime.h b/gmime/gmime.h
index 9c524e0..6c20968 100644
--- a/gmime/gmime.h
+++ b/gmime/gmime.h
@@ -71,6 +71,7 @@
 #include <gmime/gmime-filter-from.h>
 #include <gmime/gmime-filter-gzip.h>
 #include <gmime/gmime-filter-html.h>
+#include <gmime/gmime-filter-openpgp.h>
 #include <gmime/gmime-filter-smtp-data.h>
 #include <gmime/gmime-filter-strip.h>
 #include <gmime/gmime-filter-unix2dos.h>
diff --git a/tests/test-pgp.c b/tests/test-pgp.c
index b3f7c2d..3f7811c 100644
--- a/tests/test-pgp.c
+++ b/tests/test-pgp.c
@@ -329,12 +329,29 @@ import_key (GMimeCryptoContext *ctx, const char *path)
        }
 }
 
+static void
+pump_data_through_filter (GMimeFilter *filter, const char *path)
+{
+       GMimeStream *filtered, *stream;
+       
+       stream = g_mime_stream_null_new ();
+       filtered = g_mime_stream_filter_new (stream);
+       g_object_unref (stream);
+       
+       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+       
+       stream = g_mime_stream_fs_open (path, O_RDONLY, 0644, NULL);
+       g_mime_stream_write_to_stream (stream, filtered);
+       g_object_unref (filtered);
+       g_object_unref (stream);
+}
 
 int main (int argc, char **argv)
 {
 #ifdef ENABLE_CRYPTO
        const char *datadir = "data/pgp";
        GMimeStream *istream, *ostream;
+       GMimeFilterOpenPGP *filter;
        GMimeCryptoContext *ctx;
        const char *what;
        char *gpg, *key;
@@ -482,6 +499,48 @@ int main (int argc, char **argv)
        g_object_unref (ostream);
        g_object_unref (ctx);
        
+       what = "GMimeFilterOpenPGP";
+       testsuite_check ("%s", what);
+       try {
+               gint64 offset;
+               
+               filter = (GMimeFilterOpenPGP *) g_mime_filter_openpgp_new ();
+               
+               key = g_build_filename (datadir, "gmime.gpg.pub", NULL);
+               pump_data_through_filter ((GMimeFilter *) filter, key);
+               g_free (key);
+               
+               if (g_mime_filter_openpgp_get_data_type (filter) != GMIME_OPENPGP_DATA_PUBLIC_KEY)
+                       throw (exception_new ("Failed to detect public key block"));
+               
+               if ((offset = g_mime_filter_openpgp_get_begin_offset (filter)) != 0)
+                       throw (exception_new ("Incorrect public key block begin offset: %ld", (long) offset));
+               
+               if ((offset = g_mime_filter_openpgp_get_end_offset (filter)) != 1690)
+                       throw (exception_new ("Incorrect public key block end offset: %ld", (long) offset));
+               
+               g_mime_filter_reset ((GMimeFilter *) filter);
+               
+               key = g_build_filename (datadir, "gmime.gpg.sec", NULL);
+               pump_data_through_filter ((GMimeFilter *) filter, key);
+               g_free (key);
+               
+               if (g_mime_filter_openpgp_get_data_type (filter) != GMIME_OPENPGP_DATA_PRIVATE_KEY)
+                       throw (exception_new ("Failed to detect private key block"));
+               
+               if ((offset = g_mime_filter_openpgp_get_begin_offset (filter)) != 0)
+                       throw (exception_new ("Incorrect private key block begin offset: %ld", (long) 
offset));
+               
+               if ((offset = g_mime_filter_openpgp_get_end_offset (filter)) != 1895)
+                       throw (exception_new ("Incorrect private key block end offset: %ld", (long) offset));
+               
+               testsuite_check_passed ();
+       } catch (ex) {
+               testsuite_check_failed ("%s failed: %s", what, ex->message);
+       } finally;
+       
+       g_object_unref (filter);
+       
        testsuite_end ();
        
        g_mime_shutdown ();


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