[evolution-data-server] CamelMimeFilterCRLF: Correct encoding part of the filter



commit e35b15d75f66e4b1680dd4e9d5df907c8ac931a4
Author: Milan Crha <mcrha redhat com>
Date:   Fri Jan 14 13:38:56 2022 +0100

    CamelMimeFilterCRLF: Correct encoding part of the filter
    
    Some cases of the input data could produce invalid output, thus
    correct the code and add some more cases int he unit test.
    
    Related to https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/372

 src/camel/camel-mime-filter-crlf.c      | 25 +++++++++++++++++++++
 src/camel/tests/mime-filter/test-crlf.c | 40 ++++++++++++++++++++++++++++++++-
 2 files changed, 64 insertions(+), 1 deletion(-)
---
diff --git a/src/camel/camel-mime-filter-crlf.c b/src/camel/camel-mime-filter-crlf.c
index d8f93bde3..4a571e2e1 100644
--- a/src/camel/camel-mime-filter-crlf.c
+++ b/src/camel/camel-mime-filter-crlf.c
@@ -60,13 +60,21 @@ mime_filter_crlf_filter (CamelMimeFilter *mime_filter,
                outptr = mime_filter->outbuf;
                while (inptr < inend) {
                        if (*inptr == '\r') {
+                               if (priv->saw_cr && !priv->saw_lf)
+                                       *outptr++ = '\n';
                                priv->saw_cr = TRUE;
+                               priv->saw_lf = FALSE;
                        } else if (*inptr == '\n') {
                                priv->saw_lf = TRUE;
                                if (!priv->saw_cr)
                                        *outptr++ = '\r';
                                priv->saw_cr = FALSE;
                        } else {
+                               if (priv->saw_cr && !priv->saw_lf) {
+                                       priv->saw_lf = TRUE;
+                                       *outptr++ = '\n';
+                               }
+
                                if (do_dots && *inptr == '.' && priv->saw_lf)
                                        *outptr++ = '.';
 
@@ -146,6 +154,23 @@ mime_filter_crlf_complete (CamelMimeFilter *mime_filter,
 
        crlf_filter = CAMEL_MIME_FILTER_CRLF (mime_filter);
 
+       if (crlf_filter->priv->direction == CAMEL_MIME_FILTER_CRLF_ENCODE &&
+           crlf_filter->priv->saw_cr && !crlf_filter->priv->saw_lf) {
+               gchar *outptr;
+
+               camel_mime_filter_set_size (mime_filter, *outlen + 1, FALSE);
+
+               outptr = mime_filter->outbuf + *outlen;
+               *outptr++ = '\n';
+
+               *out = mime_filter->outbuf;
+               *outlen = outptr - mime_filter->outbuf;
+               *outprespace = mime_filter->outpre;
+
+               crlf_filter->priv->saw_cr = FALSE;
+               crlf_filter->priv->ends_with_lf = TRUE;
+       }
+
        if (crlf_filter->priv->direction == CAMEL_MIME_FILTER_CRLF_ENCODE &&
            crlf_filter->priv->ensure_crlf_end &&
            !crlf_filter->priv->ends_with_lf) {
diff --git a/src/camel/tests/mime-filter/test-crlf.c b/src/camel/tests/mime-filter/test-crlf.c
index 77cc7f083..82b315705 100644
--- a/src/camel/tests/mime-filter/test-crlf.c
+++ b/src/camel/tests/mime-filter/test-crlf.c
@@ -176,6 +176,22 @@ test_case (gint test_num)
        camel_test_pull ();
 }
 
+static void
+dump_data (const gchar *what,
+          const gchar *data,
+          guint len)
+{
+       guint ii;
+
+       printf ("%s %u bytes:\n", what, len);
+       for (ii = 0; ii < len; ii++) {
+               printf (" %02x", data[ii]);
+               if (!((ii + 1) % 16) && ii + 1 < len)
+                       printf ("\n");
+       }
+       printf ("\n");
+}
+
 static gboolean
 test_case_ensure_crlf_end_run (const gchar *in,
                               const gchar *expected,
@@ -209,6 +225,9 @@ test_case_ensure_crlf_end_run (const gchar *in,
                        if (!success)
                                camel_test_fail ("Returned text '%s' and expected text '%s' do not match", 
bytes, expected);
                } else {
+                       dump_data ("   Wrote", in, strlen (in));
+                       dump_data ("   Read", bytes, bytes_read);
+                       dump_data ("   Expected", expected, strlen (expected));
                        camel_test_fail ("Read %u bytes, but expected %u bytes", bytes_read, strlen 
(expected));
                }
        } else {
@@ -236,7 +255,26 @@ test_case_ensure_crlf_end (void)
                { "a\r\nb", "a\r\nb", "a\r\nb\r\n" },
                { "a\nb", "a\r\nb", "a\r\nb\r\n" },
                { "a\r\nb\n", "a\r\nb\r\n", "a\r\nb\r\n" },
-               { "a\n\nb", "a\r\n\r\nb", "a\r\n\r\nb\r\n" }
+               { "a\n\nb", "a\r\n\r\nb", "a\r\n\r\nb\r\n" },
+               { "\n", "\r\n", "\r\n" },
+               { "\r", "\r\n", "\r\n" },
+               { ".", "..", "..\r\n" },
+               { "\n.", "\r\n..", "\r\n..\r\n" },
+               { "\r.", "\r\n..", "\r\n..\r\n" },
+               { "\r\n.", "\r\n..", "\r\n..\r\n" },
+               { "a.b", "a.b", "a.b\r\n" },
+               { "\r.b", "\r\n..b", "\r\n..b\r\n" },
+               { "\n.b", "\r\n..b", "\r\n..b\r\n" },
+               { "\n.\rb", "\r\n..\r\nb", "\r\n..\r\nb\r\n" },
+               { "\n.\nb", "\r\n..\r\nb", "\r\n..\r\nb\r\n" },
+               { "\r.\nb", "\r\n..\r\nb", "\r\n..\r\nb\r\n" },
+               { "\r.\rb", "\r\n..\r\nb", "\r\n..\r\nb\r\n" },
+               { "a\r\nb\rc\nd\n\re\r\nf\ng\n\r\n\r\r\n\n\r",
+                 "a\r\nb\r\nc\r\nd\r\n\r\ne\r\nf\r\ng\r\n\r\n\r\n\r\n\r\n\r\n",
+                 "a\r\nb\r\nc\r\nd\r\n\r\ne\r\nf\r\ng\r\n\r\n\r\n\r\n\r\n\r\n" },
+               { "a\n\rb\nc\rd\r\ne\n\rf\rg\r\n\r\n\n\r\r\n",
+                 "a\r\n\r\nb\r\nc\r\nd\r\ne\r\n\r\nf\r\ng\r\n\r\n\r\n\r\n\r\n",
+                 "a\r\n\r\nb\r\nc\r\nd\r\ne\r\n\r\nf\r\ng\r\n\r\n\r\n\r\n\r\n" }
        };
        guint ii;
 


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