[gmime] Split GMimeFilterCRLF into Unix2Dos and Dos2Unix



commit 21e1d34a2d6196d1a9ada870af97b1a5c6b2b76f
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Sun Mar 19 20:15:55 2017 -0400

    Split GMimeFilterCRLF into Unix2Dos and Dos2Unix

 docs/reference/gmime-docs.sgml       |    4 +
 docs/reference/gmime-sections.txt    |   36 +++++++
 docs/reference/gmime.hierarchy       |    2 +
 gmime/Makefile.am                    |    4 +
 gmime/gmime-application-pkcs7-mime.c |   41 +++-----
 gmime/gmime-filter-dos2unix.c        |  188 ++++++++++++++++++++++++++++++++++
 gmime/gmime-filter-dos2unix.h        |   66 ++++++++++++
 gmime/gmime-filter-unix2dos.c        |  188 ++++++++++++++++++++++++++++++++++
 gmime/gmime-filter-unix2dos.h        |   66 ++++++++++++
 gmime/gmime-filter.c                 |    2 +-
 gmime/gmime-format-options.c         |    7 +-
 gmime/gmime-format-options.h         |    4 +-
 gmime/gmime-message.c                |    6 +-
 gmime/gmime-message.h                |    5 +-
 gmime/gmime-multipart-encrypted.c    |   24 ++---
 gmime/gmime-multipart-signed.c       |   29 +++--
 gmime/gmime-object.c                 |    1 +
 gmime/gmime-object.h                 |    4 +-
 gmime/gmime-parser.c                 |    2 +
 gmime/gmime-part.c                   |   77 +++++++-------
 gmime/gmime.c                        |    2 +
 gmime/gmime.h                        |    2 +
 tests/test-pgpmime.c                 |    7 +-
 23 files changed, 665 insertions(+), 102 deletions(-)
---
diff --git a/docs/reference/gmime-docs.sgml b/docs/reference/gmime-docs.sgml
index 08482bc..d167a95 100644
--- a/docs/reference/gmime-docs.sgml
+++ b/docs/reference/gmime-docs.sgml
@@ -46,12 +46,14 @@
 <!ENTITY GMimeFilterBest SYSTEM "xml/gmime-filter-best.xml">
 <!ENTITY GMimeFilterCharset SYSTEM "xml/gmime-filter-charset.xml">
 <!ENTITY GMimeFilterCRLF SYSTEM "xml/gmime-filter-crlf.xml">
+<!ENTITY GMimeFilterDos2Unix SYSTEM "xml/gmime-filter-dos2unix.xml">
 <!ENTITY GMimeFilterEnriched SYSTEM "xml/gmime-filter-enriched.xml">
 <!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 GMimeFilterMd5 SYSTEM "xml/gmime-filter-md5.xml">
 <!ENTITY GMimeFilterStrip SYSTEM "xml/gmime-filter-strip.xml">
+<!ENTITY GMimeFilterUnix2Dos SYSTEM "xml/gmime-filter-unix2dos.xml">
 <!ENTITY GMimeFilterWindows SYSTEM "xml/gmime-filter-windows.xml">
 <!ENTITY GMimeFilterYenc SYSTEM "xml/gmime-filter-yenc.xml">
 <!ENTITY GMimeCertificate SYSTEM "xml/gmime-certificate.xml">
@@ -208,12 +210,14 @@ string utilities, file utilities, a main loop abstraction, and so on.
       &GMimeFilterBest;
       &GMimeFilterCharset;
       &GMimeFilterCRLF;
+      &GMimeFilterDos2Unix;
       &GMimeFilterEnriched;
       &GMimeFilterFrom;
       &GMimeFilterGZip;
       &GMimeFilterHTML;
       &GMimeFilterMd5;
       &GMimeFilterStrip;
+      &GMimeFilterUnix2Dos;
       &GMimeFilterWindows;
       &GMimeFilterYenc;
     </chapter>
diff --git a/docs/reference/gmime-sections.txt b/docs/reference/gmime-sections.txt
index ba0c515..df3b758 100644
--- a/docs/reference/gmime-sections.txt
+++ b/docs/reference/gmime-sections.txt
@@ -369,6 +369,24 @@ GMIME_FILTER_CRLF_GET_CLASS
 </SECTION>
 
 <SECTION>
+<FILE>gmime-filter-dos2unix</FILE>
+GMimeFilterDos2Unix
+g_mime_filter_dos2unix_new
+
+<SUBSECTION Private>
+g_mime_filter_dos2unix_get_type
+
+<SUBSECTION Standard>
+GMimeFilterDos2UnixClass
+GMIME_TYPE_FILTER_DOS2UNIX
+GMIME_FILTER_DOS2UNIX
+GMIME_IS_FILTER_DOS2UNIX
+GMIME_FILTER_DOS2UNIX_CLASS
+GMIME_IS_FILTER_DOS2UNIX_CLASS
+GMIME_FILTER_DOS2UNIX_GET_CLASS
+</SECTION>
+
+<SECTION>
 <FILE>gmime-filter-enriched</FILE>
 GMIME_FILTER_ENRICHED_IS_RICHTEXT
 GMimeFilterEnriched
@@ -490,6 +508,24 @@ GMIME_FILTER_STRIP_GET_CLASS
 </SECTION>
 
 <SECTION>
+<FILE>gmime-filter-unix2dos</FILE>
+GMimeFilterUnix2Dos
+g_mime_filter_unix2dos_new
+
+<SUBSECTION Private>
+g_mime_filter_unix2dos_get_type
+
+<SUBSECTION Standard>
+GMimeFilterUnix2DosClass
+GMIME_TYPE_FILTER_UNIX2DOS
+GMIME_FILTER_UNIX2DOS
+GMIME_IS_FILTER_UNIX2DOS
+GMIME_FILTER_UNIX2DOS_CLASS
+GMIME_IS_FILTER_UNIX2DOS_CLASS
+GMIME_FILTER_UNIX2DOS_GET_CLASS
+</SECTION>
+
+<SECTION>
 <FILE>gmime-filter-windows</FILE>
 GMimeFilterWindows
 g_mime_filter_windows_new
diff --git a/docs/reference/gmime.hierarchy b/docs/reference/gmime.hierarchy
index e37ccc4..cd32079 100644
--- a/docs/reference/gmime.hierarchy
+++ b/docs/reference/gmime.hierarchy
@@ -33,12 +33,14 @@ GObject
     GMimeFilterBest
     GMimeFilterCharset
     GMimeFilterCRLF
+    GMimeFilterDos2Unix
     GMimeFilterEnriched
     GMimeFilterFrom
     GMimeFilterGZip
     GMimeFilterHTML
     GMimeFilterMd5
     GMimeFilterStrip
+    GMimeFilterUnix2Dos
     GMimeFilterWindows
     GMimeFilterYenc
   GMimeParser
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index 59f781e..cf34f9d 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -36,12 +36,14 @@ libgmime_3_0_la_SOURCES =           \
        gmime-filter-best.c             \
        gmime-filter-charset.c          \
        gmime-filter-crlf.c             \
+       gmime-filter-dos2unix.c         \
        gmime-filter-enriched.c         \
        gmime-filter-from.c             \
        gmime-filter-gzip.c             \
        gmime-filter-html.c             \
        gmime-filter-md5.c              \
        gmime-filter-strip.c            \
+       gmime-filter-unix2dos.c         \
        gmime-filter-windows.c          \
        gmime-filter-yenc.c             \
        gmime-format-options.c          \
@@ -96,12 +98,14 @@ gmimeinclude_HEADERS =                      \
        gmime-filter-best.h             \
        gmime-filter-charset.h          \
        gmime-filter-crlf.h             \
+       gmime-filter-dos2unix.h         \
        gmime-filter-enriched.h         \
        gmime-filter-from.h             \
        gmime-filter-gzip.h             \
        gmime-filter-html.h             \
        gmime-filter-md5.h              \
        gmime-filter-strip.h            \
+       gmime-filter-unix2dos.h         \
        gmime-filter-windows.h          \
        gmime-filter-yenc.h             \
        gmime-format-options.h          \
diff --git a/gmime/gmime-application-pkcs7-mime.c b/gmime/gmime-application-pkcs7-mime.c
index 0b10423..276d725 100644
--- a/gmime/gmime-application-pkcs7-mime.c
+++ b/gmime/gmime-application-pkcs7-mime.c
@@ -26,10 +26,11 @@
 #include <string.h>
 
 #include "gmime-application-pkcs7-mime.h"
+#include "gmime-filter-dos2unix.h"
 #include "gmime-stream-filter.h"
 #include "gmime-filter-basic.h"
-#include "gmime-filter-crlf.h"
 #include "gmime-stream-mem.h"
+#include "gmime-internal.h"
 #include "gmime-parser.h"
 #include "gmime-error.h"
 
@@ -227,8 +228,8 @@ g_mime_application_pkcs7_mime_decompress (GMimeApplicationPkcs7Mime *pkcs7_mime,
 GMimeApplicationPkcs7Mime *
 g_mime_application_pkcs7_mime_encrypt (GMimeObject *entity, GMimeEncryptFlags flags, GPtrArray *recipients, 
GError **err)
 {
-       GMimeStream *filtered, *ciphertext, *stream;
        GMimeApplicationPkcs7Mime *pkcs7_mime;
+       GMimeStream *ciphertext, *stream;
        GMimeContentType *content_type;
        GMimeFormatOptions *options;
        GMimeDataWrapper *content;
@@ -245,19 +246,13 @@ g_mime_application_pkcs7_mime_encrypt (GMimeObject *entity, GMimeEncryptFlags fl
                return NULL;
        }
        
-       options = g_mime_format_options_get_default ();
+       options = _g_mime_format_options_clone (NULL, FALSE);
+       g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
        
        /* get the cleartext */
        stream = g_mime_stream_mem_new ();
-       filtered = g_mime_stream_filter_new (stream);
-       
-       filter = g_mime_filter_crlf_new (TRUE, FALSE);
-       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
-       g_object_unref (filter);
-       
-       g_mime_object_write_to_stream (entity, options, filtered);
-       g_mime_stream_flush (filtered);
-       g_object_unref (filtered);
+       g_mime_object_write_to_stream (entity, options, stream);
+       g_mime_format_options_free (options);
        
        /* reset the content stream */
        g_mime_stream_reset (stream);
@@ -278,7 +273,7 @@ g_mime_application_pkcs7_mime_encrypt (GMimeObject *entity, GMimeEncryptFlags fl
        /* construct the application/pkcs7-mime part */
        pkcs7_mime = g_mime_application_pkcs7_mime_new (GMIME_SECURE_MIME_TYPE_ENVELOPED_DATA);
        content = g_mime_data_wrapper_new_with_stream (ciphertext, GMIME_CONTENT_ENCODING_DEFAULT);
-       g_mime_part_set_content (GMIME_PART (pkcs7_mime), content);
+       g_mime_part_set_content ((GMimePart *) pkcs7_mime, content);
        g_object_unref (ciphertext);
        g_object_unref (content);
        
@@ -343,7 +338,7 @@ g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime,
        
        stream = g_mime_stream_mem_new ();
        filtered = g_mime_stream_filter_new (stream);
-       filter = g_mime_filter_crlf_new (FALSE, FALSE);
+       filter = g_mime_filter_dos2unix_new (FALSE);
        g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
@@ -401,8 +396,8 @@ g_mime_application_pkcs7_mime_decrypt (GMimeApplicationPkcs7Mime *pkcs7_mime,
 GMimeApplicationPkcs7Mime *
 g_mime_application_pkcs7_mime_sign (GMimeObject *entity, const char *userid, GError **err)
 {
-       GMimeStream *filtered, *ciphertext, *stream;
        GMimeApplicationPkcs7Mime *pkcs7_mime;
+       GMimeStream *ciphertext, *stream;
        GMimeContentType *content_type;
        GMimeFormatOptions *options;
        GMimeDataWrapper *content;
@@ -419,19 +414,13 @@ g_mime_application_pkcs7_mime_sign (GMimeObject *entity, const char *userid, GEr
                return NULL;
        }
        
-       options = g_mime_format_options_get_default ();
+       options = _g_mime_format_options_clone (NULL, FALSE);
+       g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
        
        /* get the cleartext */
        stream = g_mime_stream_mem_new ();
-       filtered = g_mime_stream_filter_new (stream);
-       
-       filter = g_mime_filter_crlf_new (TRUE, FALSE);
-       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
-       g_object_unref (filter);
-       
-       g_mime_object_write_to_stream (entity, options, filtered);
-       g_mime_stream_flush (filtered);
-       g_object_unref (filtered);
+       g_mime_object_write_to_stream (entity, options, stream);
+       g_mime_format_options_free (options);
        
        /* reset the content stream */
        g_mime_stream_reset (stream);
@@ -501,7 +490,7 @@ g_mime_application_pkcs7_mime_verify (GMimeApplicationPkcs7Mime *pkcs7_mime, GMi
        
        stream = g_mime_stream_mem_new ();
        filtered = g_mime_stream_filter_new (stream);
-       filter = g_mime_filter_crlf_new (FALSE, FALSE);
+       filter = g_mime_filter_dos2unix_new (FALSE);
        g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
diff --git a/gmime/gmime-filter-dos2unix.c b/gmime/gmime-filter-dos2unix.c
new file mode 100644
index 0000000..9d7e6e0
--- /dev/null
+++ b/gmime/gmime-filter-dos2unix.c
@@ -0,0 +1,188 @@
+/* -*- 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-dos2unix.h"
+
+
+/**
+ * SECTION: gmime-filter-dos2unix
+ * @title: GMimeFilterDos2Unix
+ * @short_description: Convert line-endings from Windows/DOS (CRLF) to UNIX (LF).
+ *
+ * A #GMimeFilter for converting from DOS to UNIX line-endings.
+ **/
+
+
+static void g_mime_filter_dos2unix_class_init (GMimeFilterDos2UnixClass *klass);
+static void g_mime_filter_dos2unix_init (GMimeFilterDos2Unix *filter, GMimeFilterDos2UnixClass *klass);
+static void g_mime_filter_dos2unix_finalize (GObject *object);
+
+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_dos2unix_get_type (void)
+{
+       static GType type = 0;
+       
+       if (!type) {
+               static const GTypeInfo info = {
+                       sizeof (GMimeFilterDos2UnixClass),
+                       NULL, /* base_class_init */
+                       NULL, /* base_class_finalize */
+                       (GClassInitFunc) g_mime_filter_dos2unix_class_init,
+                       NULL, /* class_finalize */
+                       NULL, /* class_data */
+                       sizeof (GMimeFilterDos2Unix),
+                       0,    /* n_preallocs */
+                       (GInstanceInitFunc) g_mime_filter_dos2unix_init,
+               };
+               
+               type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterDos2Unix", &info, 0);
+       }
+       
+       return type;
+}
+
+
+static void
+g_mime_filter_dos2unix_class_init (GMimeFilterDos2UnixClass *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_dos2unix_init (GMimeFilterDos2Unix *filter, GMimeFilterDos2UnixClass *klass)
+{
+       filter->ensure_newline = FALSE;
+       filter->pc = '\0';
+}
+
+
+static GMimeFilter *
+filter_copy (GMimeFilter *filter)
+{
+       GMimeFilterDos2Unix *dos2unix = (GMimeFilterDos2Unix *) filter;
+       
+       return g_mime_filter_dos2unix_new (dos2unix->ensure_newline);
+}
+
+static void
+convert (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+        char **outbuf, size_t *outlen, size_t *outprespace, gboolean flush)
+{
+       GMimeFilterDos2Unix *dos2unix = (GMimeFilterDos2Unix *) filter;
+       register const char *inptr = inbuf;
+       const char *inend = inbuf + inlen;
+       size_t expected = inlen;
+       char *outptr;
+       
+       if (flush && dos2unix->ensure_newline)
+               expected++;
+       
+       if (dos2unix->pc == '\r')
+               expected++;
+       
+       g_mime_filter_set_size (filter, expected, FALSE);
+       
+       outptr = filter->outbuf;
+       while (inptr < inend) {
+               if (*inptr == '\n') {
+                       *outptr++ = *inptr;
+               } else {
+                       if (dos2unix->pc == '\r')
+                               *outptr++ = dos2unix->pc;
+                       
+                       if (*inptr != '\r')
+                               *outptr++ = *inptr;
+               }
+               
+               dos2unix->pc = *inptr++;
+       }
+       
+       if (flush && dos2unix->ensure_newline && dos2unix->pc != '\n')
+               dos2unix->pc = *outptr++ = '\n';
+       
+       *outlen = outptr - filter->outbuf;
+       *outprespace = filter->outpre;
+       *outbuf = filter->outbuf;
+}
+
+static void
+filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+              char **outbuf, size_t *outlen, size_t *outprespace)
+{
+       convert (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)
+{
+       convert (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace, TRUE);
+}
+
+static void
+filter_reset (GMimeFilter *filter)
+{
+       GMimeFilterDos2Unix *dos2unix = (GMimeFilterDos2Unix *) filter;
+       
+       dos2unix->pc = '\0';
+}
+
+
+/**
+ * g_mime_filter_dos2unix_new:
+ * @ensure_newline: %TRUE if the filter should ensure that the stream ends in a new line
+ *
+ * Creates a new #GMimeFilterDos2Unix filter.
+ *
+ * Returns: a new #GMimeFilterDos2Unix filter.
+ **/
+GMimeFilter *
+g_mime_filter_dos2unix_new (gboolean ensure_newline)
+{
+       GMimeFilterDos2Unix *dos2unix;
+       
+       dos2unix = g_object_newv (GMIME_TYPE_FILTER_DOS2UNIX, 0, NULL);
+       dos2unix->ensure_newline = ensure_newline;
+       
+       return (GMimeFilter *) dos2unix;
+}
diff --git a/gmime/gmime-filter-dos2unix.h b/gmime/gmime-filter-dos2unix.h
new file mode 100644
index 0000000..1e7960f
--- /dev/null
+++ b/gmime/gmime-filter-dos2unix.h
@@ -0,0 +1,66 @@
+/* -*- 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_DOS2UNIX_H__
+#define __GMIME_FILTER_DOS2UNIX_H__
+
+#include <gmime/gmime-filter.h>
+
+G_BEGIN_DECLS
+
+#define GMIME_TYPE_FILTER_DOS2UNIX            (g_mime_filter_dos2unix_get_type ())
+#define GMIME_FILTER_DOS2UNIX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GMIME_TYPE_FILTER_DOS2UNIX, GMimeFilterDos2Unix))
+#define GMIME_FILTER_DOS2UNIX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GMIME_TYPE_FILTER_DOS2UNIX, 
GMimeFilterDos2UnixClass))
+#define GMIME_IS_FILTER_DOS2UNIX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GMIME_TYPE_FILTER_DOS2UNIX))
+#define GMIME_IS_FILTER_DOS2UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GMIME_TYPE_FILTER_DOS2UNIX))
+#define GMIME_FILTER_DOS2UNIX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GMIME_TYPE_FILTER_DOS2UNIX, 
GMimeFilterDos2UnixClass))
+
+typedef struct _GMimeFilterDos2Unix GMimeFilterDos2Unix;
+typedef struct _GMimeFilterDos2UnixClass GMimeFilterDos2UnixClass;
+
+/**
+ * GMimeFilterDos2Unix:
+ * @parent_object: parent #GMimeFilter
+ * @ensure_newline: %TRUE if the filter should ensure that the stream ends with a new line
+ * @pc: the previous character encountered
+ *
+ * A filter to convert a stream from Windows/DOS line endings to Unix line endings.
+ **/
+struct _GMimeFilterDos2Unix {
+       GMimeFilter parent_object;
+       
+       gboolean ensure_newline;
+       char pc;
+};
+
+struct _GMimeFilterDos2UnixClass {
+       GMimeFilterClass parent_class;
+       
+};
+
+
+GType g_mime_filter_dos2unix_get_type (void);
+
+GMimeFilter *g_mime_filter_dos2unix_new (gboolean ensure_newline);
+
+G_END_DECLS
+
+#endif /* __GMIME_FILTER_DOS2UNIX_H__ */
diff --git a/gmime/gmime-filter-unix2dos.c b/gmime/gmime-filter-unix2dos.c
new file mode 100644
index 0000000..f1d6865
--- /dev/null
+++ b/gmime/gmime-filter-unix2dos.c
@@ -0,0 +1,188 @@
+/* -*- 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-unix2dos.h"
+
+
+/**
+ * SECTION: gmime-filter-unix2dos
+ * @title: GMimeFilterUnix2Dos
+ * @short_description: Convert line-endings from UNIX (LF) to Windows/DOS (CRLF).
+ *
+ * A #GMimeFilter for converting from UNIX to DOS line-endings.
+ **/
+
+
+static void g_mime_filter_unix2dos_class_init (GMimeFilterUnix2DosClass *klass);
+static void g_mime_filter_unix2dos_init (GMimeFilterUnix2Dos *filter, GMimeFilterUnix2DosClass *klass);
+static void g_mime_filter_unix2dos_finalize (GObject *object);
+
+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_unix2dos_get_type (void)
+{
+       static GType type = 0;
+       
+       if (!type) {
+               static const GTypeInfo info = {
+                       sizeof (GMimeFilterUnix2DosClass),
+                       NULL, /* base_class_init */
+                       NULL, /* base_class_finalize */
+                       (GClassInitFunc) g_mime_filter_unix2dos_class_init,
+                       NULL, /* class_finalize */
+                       NULL, /* class_data */
+                       sizeof (GMimeFilterUnix2Dos),
+                       0,    /* n_preallocs */
+                       (GInstanceInitFunc) g_mime_filter_unix2dos_init,
+               };
+               
+               type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterUnix2Dos", &info, 0);
+       }
+       
+       return type;
+}
+
+
+static void
+g_mime_filter_unix2dos_class_init (GMimeFilterUnix2DosClass *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_unix2dos_init (GMimeFilterUnix2Dos *filter, GMimeFilterUnix2DosClass *klass)
+{
+       filter->ensure_newline = FALSE;
+       filter->pc = '\0';
+}
+
+
+static GMimeFilter *
+filter_copy (GMimeFilter *filter)
+{
+       GMimeFilterUnix2Dos *unix2dos = (GMimeFilterUnix2Dos *) filter;
+       
+       return g_mime_filter_unix2dos_new (unix2dos->ensure_newline);
+}
+
+static void
+convert (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+        char **outbuf, size_t *outlen, size_t *outprespace, gboolean flush)
+{
+       GMimeFilterUnix2Dos *unix2dos = (GMimeFilterUnix2Dos *) filter;
+       register const char *inptr = inbuf;
+       const char *inend = inbuf + inlen;
+       size_t expected = inlen * 2;
+       char *outptr;
+       
+       if (flush && unix2dos->ensure_newline)
+               expected += 2;
+       
+       g_mime_filter_set_size (filter, expected, FALSE);
+       
+       outptr = filter->outbuf;
+       while (inptr < inend) {
+               if (*inptr == '\r') {
+                       *outptr++ = *inptr;
+               } else if (*inptr == '\n') {
+                       if (unix2dos->pc != '\r')
+                               *outptr++ = '\r';
+                       *outptr++ = *inptr;
+               } else {
+                       *outptr++ = *inptr;
+               }
+               
+               unix2dos->pc = *inptr++;
+       }
+       
+       if (flush && unix2dos->ensure_newline && unix2dos->pc != '\n') {
+               if (unix2dos->pc != '\r')
+                       *outptr++ = '\r';
+               *outptr++ = '\n';
+       }
+       
+       *outlen = outptr - filter->outbuf;
+       *outprespace = filter->outpre;
+       *outbuf = filter->outbuf;
+}
+
+static void
+filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
+              char **outbuf, size_t *outlen, size_t *outprespace)
+{
+       convert (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)
+{
+       convert (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace, TRUE);
+}
+
+static void
+filter_reset (GMimeFilter *filter)
+{
+       GMimeFilterUnix2Dos *unix2dos = (GMimeFilterUnix2Dos *) filter;
+       
+       unix2dos->pc = '\0';
+}
+
+
+/**
+ * g_mime_filter_unix2dos_new:
+ * @ensure_newline: %TRUE if the filter should ensure that the stream ends in a new line
+ *
+ * Creates a new #GMimeFilterUnix2Dos filter.
+ *
+ * Returns: a new #GMimeFilterUnix2Dos filter.
+ **/
+GMimeFilter *
+g_mime_filter_unix2dos_new (gboolean ensure_newline)
+{
+       GMimeFilterUnix2Dos *unix2dos;
+       
+       unix2dos = g_object_newv (GMIME_TYPE_FILTER_UNIX2DOS, 0, NULL);
+       unix2dos->ensure_newline = ensure_newline;
+       
+       return (GMimeFilter *) unix2dos;
+}
diff --git a/gmime/gmime-filter-unix2dos.h b/gmime/gmime-filter-unix2dos.h
new file mode 100644
index 0000000..7b8246d
--- /dev/null
+++ b/gmime/gmime-filter-unix2dos.h
@@ -0,0 +1,66 @@
+/* -*- 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_UNIX2DOS_H__
+#define __GMIME_FILTER_UNIX2DOS_H__
+
+#include <gmime/gmime-filter.h>
+
+G_BEGIN_DECLS
+
+#define GMIME_TYPE_FILTER_UNIX2DOS            (g_mime_filter_unix2dos_get_type ())
+#define GMIME_FILTER_UNIX2DOS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GMIME_TYPE_FILTER_UNIX2DOS, GMimeFilterUnix2Dos))
+#define GMIME_FILTER_UNIX2DOS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GMIME_TYPE_FILTER_UNIX2DOS, 
GMimeFilterUnix2DosClass))
+#define GMIME_IS_FILTER_UNIX2DOS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GMIME_TYPE_FILTER_UNIX2DOS))
+#define GMIME_IS_FILTER_UNIX2DOS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GMIME_TYPE_FILTER_UNIX2DOS))
+#define GMIME_FILTER_UNIX2DOS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GMIME_TYPE_FILTER_UNIX2DOS, 
GMimeFilterUnix2DosClass))
+
+typedef struct _GMimeFilterUnix2Dos GMimeFilterUnix2Dos;
+typedef struct _GMimeFilterUnix2DosClass GMimeFilterUnix2DosClass;
+
+/**
+ * GMimeFilterUnix2Dos:
+ * @parent_object: parent #GMimeFilter
+ * @ensure_newline: %TRUE if the filter should ensure that the stream ends with a new line
+ * @pc: the previous character encountered
+ *
+ * A filter to convert a stream from Windows/DOS line endings to Unix line endings.
+ **/
+struct _GMimeFilterUnix2Dos {
+       GMimeFilter parent_object;
+       
+       gboolean ensure_newline;
+       char pc;
+};
+
+struct _GMimeFilterUnix2DosClass {
+       GMimeFilterClass parent_class;
+       
+};
+
+
+GType g_mime_filter_unix2dos_get_type (void);
+
+GMimeFilter *g_mime_filter_unix2dos_new (gboolean ensure_newline);
+
+G_END_DECLS
+
+#endif /* __GMIME_FILTER_UNIX2DOS_H__ */
diff --git a/gmime/gmime-filter.c b/gmime/gmime-filter.c
index e57563d..e43e470 100644
--- a/gmime/gmime-filter.c
+++ b/gmime/gmime-filter.c
@@ -143,7 +143,7 @@ filter_copy (GMimeFilter *filter)
  * g_mime_filter_copy:
  * @filter: filter
  *
- * Copies @filter into a new GMimeFilter object.
+ * Copies @filter into a new #GMimeFilter object.
  *
  * Returns: (transfer full): a duplicate of @filter.
  **/
diff --git a/gmime/gmime-format-options.c b/gmime/gmime-format-options.c
index a7e2e67..500503d 100644
--- a/gmime/gmime-format-options.c
+++ b/gmime/gmime-format-options.c
@@ -26,7 +26,8 @@
 #include <string.h>
 
 #include "gmime-format-options.h"
-#include "gmime-filter-crlf.h"
+#include "gmime-filter-dos2unix.h"
+#include "gmime-filter-unix2dos.h"
 
 
 static GMimeFormatOptions *default_options = NULL;
@@ -269,9 +270,9 @@ g_mime_format_options_create_newline_filter (GMimeFormatOptions *options, gboole
                options = default_options;
        
        if (options->newline == GMIME_NEWLINE_FORMAT_DOS)
-               return g_mime_filter_crlf_new (TRUE, FALSE);
+               return g_mime_filter_unix2dos_new (ensure_newline);
        
-       return g_mime_filter_crlf_new (FALSE, FALSE);
+       return g_mime_filter_dos2unix_new (ensure_newline);
 }
 
 
diff --git a/gmime/gmime-format-options.h b/gmime/gmime-format-options.h
index 83c4366..870b7d3 100644
--- a/gmime/gmime-format-options.h
+++ b/gmime/gmime-format-options.h
@@ -91,8 +91,8 @@ void g_mime_format_options_free (GMimeFormatOptions *options);
 GMimeParamEncodingMethod g_mime_format_options_get_param_encoding_method (GMimeFormatOptions *options);
 void g_mime_format_options_set_param_encoding_method (GMimeFormatOptions *options, GMimeParamEncodingMethod 
method);
 
-GMimeNewLineFormat g_mime_format_get_newline_format (GMimeFormatOptions *options);
-void g_mime_format_set_newline_format (GMimeFormatOptions *options, GMimeNewLineFormat newline);
+GMimeNewLineFormat g_mime_format_options_get_newline_format (GMimeFormatOptions *options);
+void g_mime_format_options_set_newline_format (GMimeFormatOptions *options, GMimeNewLineFormat newline);
 
 const char *g_mime_format_options_get_newline (GMimeFormatOptions *options);
 GMimeFilter *g_mime_format_options_create_newline_filter (GMimeFormatOptions *options, gboolean 
ensure_newline);
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index 89e0b8d..3bad84d 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -207,6 +207,7 @@ g_mime_message_init (GMimeMessage *message, GMimeMessageClass *klass)
        guint i;
        
        message->addrlists = g_new (InternetAddressList *, N_ADDRESS_TYPES);
+       message->compliance = GMIME_RFC_COMPLIANCE_STRICT;
        message->message_id = NULL;
        message->mime_part = NULL;
        message->subject = NULL;
@@ -979,8 +980,11 @@ message_write_to_stream (GMimeObject *object, GMimeFormatOptions *options, gbool
                GMimeObjectClass *klass = GMIME_OBJECT_GET_CLASS (mime_part);
                
                options = _g_mime_format_options_clone (options, FALSE);
+               mime_part->ensure_newline = message->compliance == GMIME_RFC_COMPLIANCE_STRICT;
+               nwritten = klass->write_to_stream (mime_part, options, TRUE, stream);
+               mime_part->ensure_newline = FALSE;
                
-               if ((nwritten = klass->write_to_stream (mime_part, options, TRUE, stream)) == -1)
+               if (nwritten == -1)
                        return -1;
                
                total += nwritten;
diff --git a/gmime/gmime-message.h b/gmime/gmime-message.h
index ddfcd2b..bd59f22 100644
--- a/gmime/gmime-message.h
+++ b/gmime/gmime-message.h
@@ -85,8 +85,11 @@ struct _GMimeMessage {
        char *message_id;
        char *subject;
        
-       time_t date;
        int tz_offset;
+       time_t date;
+       
+       /* < private > */
+       GMimeRfcComplianceMode compliance;
 };
 
 struct _GMimeMessageClass {
diff --git a/gmime/gmime-multipart-encrypted.c b/gmime/gmime-multipart-encrypted.c
index dcc362b..084dd5c 100644
--- a/gmime/gmime-multipart-encrypted.c
+++ b/gmime/gmime-multipart-encrypted.c
@@ -27,11 +27,12 @@
 #include <string.h>
 
 #include "gmime-multipart-encrypted.h"
+#include "gmime-filter-dos2unix.h"
 #include "gmime-stream-filter.h"
 #include "gmime-filter-basic.h"
 #include "gmime-filter-from.h"
-#include "gmime-filter-crlf.h"
 #include "gmime-stream-mem.h"
+#include "gmime-internal.h"
 #include "gmime-parser.h"
 #include "gmime-part.h"
 #include "gmime-error.h"
@@ -158,12 +159,11 @@ GMimeMultipartEncrypted *
 g_mime_multipart_encrypted_encrypt (GMimeCryptoContext *ctx, GMimeObject *entity, gboolean sign, const char 
*userid,
                                    GMimeEncryptFlags flags, GPtrArray *recipients, GError **err)
 {
-       GMimeParserOptions *options = g_mime_parser_options_get_default ();
-       GMimeFormatOptions *format = g_mime_format_options_get_default ();
-       GMimeStream *filtered, *stream, *ciphertext;
        GMimePart *version_part, *encrypted_part;
        GMimeMultipartEncrypted *encrypted;
+       GMimeStream *stream, *ciphertext;
        GMimeContentType *content_type;
+       GMimeFormatOptions *options;
        GMimeDataWrapper *content;
        const char *protocol;
        GMimeFilter *filter;
@@ -178,15 +178,11 @@ g_mime_multipart_encrypted_encrypt (GMimeCryptoContext *ctx, GMimeObject *entity
        
        /* get the cleartext */
        stream = g_mime_stream_mem_new ();
-       filtered = g_mime_stream_filter_new (stream);
        
-       filter = g_mime_filter_crlf_new (TRUE, FALSE);
-       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
-       g_object_unref (filter);
+       options = _g_mime_format_options_clone (NULL, FALSE);
+       g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
        
-       g_mime_object_write_to_stream (entity, format, filtered);
-       g_mime_stream_flush (filtered);
-       g_object_unref (filtered);
+       g_mime_object_write_to_stream (entity, options, stream);
        
        /* reset the content stream */
        g_mime_stream_reset (stream);
@@ -203,12 +199,10 @@ g_mime_multipart_encrypted_encrypt (GMimeCryptoContext *ctx, GMimeObject *entity
        g_mime_stream_reset (ciphertext);
        
        /* construct the version part */
-       content_type = g_mime_content_type_parse (options, protocol);
+       content_type = g_mime_content_type_parse (NULL, protocol);
        version_part = g_mime_part_new_with_type (content_type->type, content_type->subtype);
        g_object_unref (content_type);
        
-       content_type = g_mime_content_type_parse (options, protocol);
-       g_mime_object_set_content_type ((GMimeObject *) version_part, content_type);
        g_mime_part_set_content_encoding (version_part, GMIME_CONTENT_ENCODING_7BIT);
        stream = g_mime_stream_mem_new_with_buffer ("Version: 1\n", strlen ("Version: 1\n"));
        content = g_mime_data_wrapper_new_with_stream (stream, GMIME_CONTENT_ENCODING_7BIT);
@@ -346,7 +340,7 @@ g_mime_multipart_encrypted_decrypt (GMimeMultipartEncrypted *encrypted, GMimeDec
        
        stream = g_mime_stream_mem_new ();
        filtered = g_mime_stream_filter_new (stream);
-       filter = g_mime_filter_crlf_new (FALSE, FALSE);
+       filter = g_mime_filter_dos2unix_new (FALSE);
        g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
diff --git a/gmime/gmime-multipart-signed.c b/gmime/gmime-multipart-signed.c
index a02bf14..7f87e39 100644
--- a/gmime/gmime-multipart-signed.c
+++ b/gmime/gmime-multipart-signed.c
@@ -29,10 +29,11 @@
 #include "gmime-multipart-encrypted.h"
 #include "gmime-message-part.h"
 #include "gmime-stream-filter.h"
+#include "gmime-filter-unix2dos.h"
 #include "gmime-filter-strip.h"
 #include "gmime-filter-from.h"
-#include "gmime-filter-crlf.h"
 #include "gmime-stream-mem.h"
+#include "gmime-internal.h"
 #include "gmime-parser.h"
 #include "gmime-error.h"
 #include "gmime-part.h"
@@ -211,8 +212,6 @@ GMimeMultipartSigned *
 g_mime_multipart_signed_sign (GMimeCryptoContext *ctx, GMimeObject *entity,
                              const char *userid, GError **err)
 {
-       GMimeParserOptions *options = g_mime_parser_options_get_default ();
-       GMimeFormatOptions *format = g_mime_format_options_get_default ();
        GMimeStream *stream, *filtered, *sigstream;
        GMimeContentType *content_type;
        GMimeDataWrapper *content;
@@ -249,14 +248,17 @@ g_mime_multipart_signed_sign (GMimeCryptoContext *ctx, GMimeObject *entity,
        g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
-       g_mime_object_write_to_stream (entity, format, filtered);
+       /* write the entity out to the stream */
+       g_mime_object_write_to_stream (entity, NULL, filtered);
        g_mime_stream_flush (filtered);
        g_mime_stream_reset (stream);
        g_object_unref (filtered);
        
-       /* Note: see rfc2015 or rfc3156, section 5.1 */
+       /* Note: see rfc2015 or rfc3156, section 5.1 - we do this *after* writing out
+        * the entity because we'll end up parsing the mime part back out again and
+        * we don't want it to be in DOS format. */
        filtered = g_mime_stream_filter_new (stream);
-       filter = g_mime_filter_crlf_new (TRUE, FALSE);
+       filter = g_mime_filter_unix2dos_new (FALSE);
        g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
        
@@ -282,7 +284,7 @@ g_mime_multipart_signed_sign (GMimeCryptoContext *ctx, GMimeObject *entity,
        g_object_unref (parser);
        
        /* construct the signature part */
-       content_type = g_mime_content_type_parse (options, protocol);
+       content_type = g_mime_content_type_parse (NULL, protocol);
        signature = g_mime_part_new_with_type (content_type->type, content_type->subtype);
        g_object_unref (content_type);
        
@@ -368,11 +370,11 @@ check_protocol_supported (const char *protocol, const char *supported)
 GMimeSignatureList *
 g_mime_multipart_signed_verify (GMimeMultipartSigned *mps, GMimeVerifyFlags flags, GError **err)
 {
-       GMimeFormatOptions *options = g_mime_format_options_get_default ();
        GMimeStream *filtered, *stream, *sigstream;
        const char *supported, *protocol;
        GMimeObject *content, *signature;
        GMimeSignatureList *signatures;
+       GMimeFormatOptions *options;
        GMimeDataWrapper *wrapper;
        GMimeCryptoContext *ctx;
        GMimeDigestAlgo digest;
@@ -435,14 +437,17 @@ g_mime_multipart_signed_verify (GMimeMultipartSigned *mps, GMimeVerifyFlags flag
        filtered = g_mime_stream_filter_new (stream);
        
        /* Note: see rfc2015 or rfc3156, section 5.1 */
-       filter = g_mime_filter_crlf_new (TRUE, FALSE);
+       filter = g_mime_filter_unix2dos_new (FALSE);
        g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        g_object_unref (filter);
+       // FIXME: use the GMimeFormatOptions...
+       //options = _g_mime_format_options_clone (NULL, FALSE);
+       //g_mime_format_options_set_newline_format (options, GMIME_NEWLINE_FORMAT_DOS);
        
-       g_mime_object_write_to_stream (content, options, filtered);
-       g_mime_stream_flush (filtered);
-       g_object_unref (filtered);
+       g_mime_object_write_to_stream (content, NULL, filtered);
+       //g_mime_format_options_free (options);
        g_mime_stream_reset (stream);
+       g_object_unref (filtered);
        
        /* get the signature stream */
        wrapper = g_mime_part_get_content ((GMimePart *) signature);
diff --git a/gmime/gmime-object.c b/gmime/gmime-object.c
index b321a86..d119f8a 100644
--- a/gmime/gmime-object.c
+++ b/gmime/gmime-object.c
@@ -142,6 +142,7 @@ g_mime_object_init (GMimeObject *object, GMimeObjectClass *klass)
        g_mime_event_add (headers->changed, (GMimeEventCallback) header_list_changed, object);
        object->headers = headers;
        
+       object->ensure_newline = FALSE;
        object->content_type = NULL;
        object->disposition = NULL;
        object->content_id = NULL;
diff --git a/gmime/gmime-object.h b/gmime/gmime-object.h
index ed82fd8..f02d069 100644
--- a/gmime/gmime-object.h
+++ b/gmime/gmime-object.h
@@ -61,8 +61,10 @@ struct _GMimeObject {
        GMimeContentDisposition *disposition;
        GMimeContentType *content_type;
        GMimeHeaderList *headers;
-       
        char *content_id;
+       
+       /* < private > */
+       gboolean ensure_newline;
 };
 
 struct _GMimeObjectClass {
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index fc683a8..3da3018 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -1692,6 +1692,7 @@ parser_scan_message_part (GMimeParser *parser, GMimeParserOptions *options, GMim
        }
        
        message = g_mime_message_new (FALSE);
+       message->compliance = GMIME_RFC_COMPLIANCE_LOOSE;
        header = priv->headers;
        while (header) {
                if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0) {
@@ -2005,6 +2006,7 @@ parser_construct_message (GMimeParser *parser, GMimeParserOptions *options)
        }
        
        message = g_mime_message_new (FALSE);
+       message->compliance = GMIME_RFC_COMPLIANCE_LOOSE;
        header = priv->headers;
        while (header) {
                if (priv->respect_content_length && !g_ascii_strcasecmp (header->name, "Content-Length")) {
diff --git a/gmime/gmime-part.c b/gmime/gmime-part.c
index 96a6f3c..e0419ef 100644
--- a/gmime/gmime-part.c
+++ b/gmime/gmime-part.c
@@ -37,8 +37,8 @@
 #include "gmime-stream-filter.h"
 #include "gmime-filter-basic.h"
 #include "gmime-filter-best.h"
-#include "gmime-filter-crlf.h"
 #include "gmime-filter-md5.h"
+#include "gmime-filter-unix2dos.h"
 #include "gmime-table-private.h"
 
 #define _(x) x
@@ -301,6 +301,7 @@ mime_part_headers_cleared (GMimeObject *object)
 static ssize_t
 write_content (GMimePart *part, GMimeFormatOptions *options, GMimeStream *stream)
 {
+       GMimeObject *object = (GMimeObject *) part;
        ssize_t nwritten, total = 0;
        GMimeStream *filtered;
        GMimeFilter *filter;
@@ -341,9 +342,11 @@ write_content (GMimePart *part, GMimeFormatOptions *options, GMimeStream *stream
                        break;
                }
                
-               filter = g_mime_format_options_create_newline_filter (options, FALSE);
-               g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
-               g_object_unref (filter);
+               if (part->encoding != GMIME_CONTENT_ENCODING_BINARY) {
+                       filter = g_mime_format_options_create_newline_filter (options, 
object->ensure_newline);
+                       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+                       g_object_unref (filter);
+               }
                
                nwritten = g_mime_data_wrapper_write_to_stream (part->content, filtered);
                g_mime_stream_flush (filtered);
@@ -367,11 +370,15 @@ write_content (GMimePart *part, GMimeFormatOptions *options, GMimeStream *stream
                g_mime_stream_reset (content);
                
                filtered = g_mime_stream_filter_new (stream);
-               filter = g_mime_format_options_create_newline_filter (options, FALSE);
-               g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
-               g_object_unref (filter);
+               
+               if (part->encoding != GMIME_CONTENT_ENCODING_BINARY) {
+                       filter = g_mime_format_options_create_newline_filter (options, 
object->ensure_newline);
+                       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+                       g_object_unref (filter);
+               }
                
                nwritten = g_mime_stream_write_to_stream (content, filtered);
+               g_mime_stream_flush (filtered);
                g_mime_stream_reset (content);
                g_object_unref (filtered);
                
@@ -603,10 +610,9 @@ g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5)
 {
        GMimeObject *object = (GMimeObject *) mime_part;
        unsigned char digest[16], b64digest[32];
-       GMimeStreamFilter *filtered_stream;
        GMimeContentType *content_type;
-       GMimeFilter *md5_filter;
-       GMimeStream *stream;
+       GMimeStream *filtered, *stream;
+       GMimeFilter *filter;
        guint32 save = 0;
        int state = 0;
        size_t len;
@@ -618,28 +624,25 @@ g_mime_part_set_content_md5 (GMimePart *mime_part, const char *content_md5)
        if (!content_md5) {
                /* compute a md5sum */
                stream = g_mime_stream_null_new ();
-               filtered_stream = (GMimeStreamFilter *) g_mime_stream_filter_new (stream);
+               filtered = g_mime_stream_filter_new (stream);
                g_object_unref (stream);
                
                content_type = g_mime_object_get_content_type ((GMimeObject *) mime_part);
                if (g_mime_content_type_is_type (content_type, "text", "*")) {
-                       GMimeFilter *crlf_filter;
-                       
-                       crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE);
-                       g_mime_stream_filter_add (filtered_stream, crlf_filter);
-                       g_object_unref (crlf_filter);
+                       filter = g_mime_filter_unix2dos_new (FALSE);
+                       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+                       g_object_unref (filter);
                }
                
-               md5_filter = g_mime_filter_md5_new ();
-               g_mime_stream_filter_add (filtered_stream, md5_filter);
+               filter = g_mime_filter_md5_new ();
+               g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
                
-               stream = (GMimeStream *) filtered_stream;
-               g_mime_data_wrapper_write_to_stream (mime_part->content, stream);
-               g_object_unref (stream);
+               g_mime_data_wrapper_write_to_stream (mime_part->content, filtered);
+               g_object_unref (filtered);
                
                memset (digest, 0, 16);
-               g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) md5_filter, digest);
-               g_object_unref (md5_filter);
+               g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) filter, digest);
+               g_object_unref (filter);
                
                len = g_mime_encoding_base64_encode_close (digest, 16, b64digest, &state, &save);
                b64digest[len] = '\0';
@@ -669,10 +672,9 @@ gboolean
 g_mime_part_verify_content_md5 (GMimePart *mime_part)
 {
        unsigned char digest[16], b64digest[32];
-       GMimeStreamFilter *filtered_stream;
        GMimeContentType *content_type;
-       GMimeFilter *md5_filter;
-       GMimeStream *stream;
+       GMimeStream *filtered, *stream;
+       GMimeFilter *filter;
        guint32 save = 0;
        int state = 0;
        size_t len;
@@ -684,28 +686,25 @@ g_mime_part_verify_content_md5 (GMimePart *mime_part)
                return FALSE;
        
        stream = g_mime_stream_null_new ();
-       filtered_stream = (GMimeStreamFilter *) g_mime_stream_filter_new (stream);
+       filtered = g_mime_stream_filter_new (stream);
        g_object_unref (stream);
        
        content_type = g_mime_object_get_content_type ((GMimeObject *) mime_part);
        if (g_mime_content_type_is_type (content_type, "text", "*")) {
-               GMimeFilter *crlf_filter;
-               
-               crlf_filter = g_mime_filter_crlf_new (TRUE, FALSE);
-               g_mime_stream_filter_add (filtered_stream, crlf_filter);
-               g_object_unref (crlf_filter);
+               filter = g_mime_filter_unix2dos_new (FALSE);
+               g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
+               g_object_unref (filter);
        }
        
-       md5_filter = g_mime_filter_md5_new ();
-       g_mime_stream_filter_add (filtered_stream, md5_filter);
+       filter = g_mime_filter_md5_new ();
+       g_mime_stream_filter_add ((GMimeStreamFilter *) filtered, filter);
        
-       stream = (GMimeStream *) filtered_stream;
-       g_mime_data_wrapper_write_to_stream (mime_part->content, stream);
-       g_object_unref (stream);
+       g_mime_data_wrapper_write_to_stream (mime_part->content, filtered);
+       g_object_unref (filtered);
        
        memset (digest, 0, 16);
-       g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) md5_filter, digest);
-       g_object_unref (md5_filter);
+       g_mime_filter_md5_get_digest ((GMimeFilterMd5 *) filter, digest);
+       g_object_unref (filter);
        
        len = g_mime_encoding_base64_encode_close (digest, 16, b64digest, &state, &save);
        b64digest[len] = '\0';
diff --git a/gmime/gmime.c b/gmime/gmime.c
index 9fcc858..77cea63 100644
--- a/gmime/gmime.c
+++ b/gmime/gmime.c
@@ -147,12 +147,14 @@ g_mime_init (void)
        g_mime_filter_best_get_type ();
        g_mime_filter_charset_get_type ();
        g_mime_filter_crlf_get_type ();
+       g_mime_filter_dos2unix_get_type ();
        g_mime_filter_enriched_get_type ();
        g_mime_filter_from_get_type ();
        g_mime_filter_gzip_get_type ();
        g_mime_filter_html_get_type ();
        g_mime_filter_md5_get_type ();
        g_mime_filter_strip_get_type ();
+       g_mime_filter_unix2dos_get_type ();
        g_mime_filter_windows_get_type ();
        g_mime_filter_yenc_get_type ();
        
diff --git a/gmime/gmime.h b/gmime/gmime.h
index 84717d4..d1a4764 100644
--- a/gmime/gmime.h
+++ b/gmime/gmime.h
@@ -65,12 +65,14 @@
 #include <gmime/gmime-filter-best.h>
 #include <gmime/gmime-filter-charset.h>
 #include <gmime/gmime-filter-crlf.h>
+#include <gmime/gmime-filter-dos2unix.h>
 #include <gmime/gmime-filter-enriched.h>
 #include <gmime/gmime-filter-from.h>
 #include <gmime/gmime-filter-gzip.h>
 #include <gmime/gmime-filter-html.h>
 #include <gmime/gmime-filter-md5.h>
 #include <gmime/gmime-filter-strip.h>
+#include <gmime/gmime-filter-unix2dos.h>
 #include <gmime/gmime-filter-windows.h>
 #include <gmime/gmime-filter-yenc.h>
 #include <gmime/gmime-crypto-context.h>
diff --git a/tests/test-pgpmime.c b/tests/test-pgpmime.c
index 45f5e6c..014668f 100644
--- a/tests/test-pgpmime.c
+++ b/tests/test-pgpmime.c
@@ -221,6 +221,7 @@ static void
 test_multipart_signed (GMimeCryptoContext *ctx)
 {
        GMimeSignatureList *signatures;
+       GMimeSignatureStatus status;
        GMimeMultipartSigned *mps;
        GMimeMessage *message;
        GMimeTextPart *part;
@@ -259,9 +260,13 @@ test_multipart_signed (GMimeCryptoContext *ctx)
        }
        
        v(print_verify_results (signatures));
-       g_object_unref (signatures);
        
+       status = get_sig_status (signatures);
+       g_object_unref (signatures);
        g_object_unref (message);
+       
+       if (status & GMIME_SIGNATURE_STATUS_RED)
+               throw (exception_new ("signature status was BAD"));
 }
 
 #define MULTIPART_ENCRYPTED_CONTENT "This is a test of multipart/encrypted.\n"



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