[geary/mjog/server-quirks: 3/4] Geary.Imap.Deserialiser: Handle reserved chars in response-text



commit 44e192d9d2f8c18643857a566401a9a8fc72e3c5
Author: Michael Gratton <mike vee net>
Date:   Sat May 2 17:13:54 2020 +1000

    Geary.Imap.Deserialiser: Handle reserved chars in response-text
    
    RFC 3501 allows any kind of char except CRLF in `resp-text` after an
    optional response code, so handle that.
    
    Addresses another issue in #711

 src/engine/imap/transport/imap-deserializer.vala   | 30 +++++++++++++++++++---
 .../imap/transport/imap-deserializer-test.vala     | 18 +++++++++++--
 2 files changed, 42 insertions(+), 6 deletions(-)
---
diff --git a/src/engine/imap/transport/imap-deserializer.vala 
b/src/engine/imap/transport/imap-deserializer.vala
index 72e739eb..70079e09 100644
--- a/src/engine/imap/transport/imap-deserializer.vala
+++ b/src/engine/imap/transport/imap-deserializer.vala
@@ -30,6 +30,10 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
 
     private const size_t MAX_BLOCK_READ_SIZE = 4096;
 
+    private const string[] RESPONSE_ATOMS = {
+        "OK", "NO", "BAD", "BYE", "PREAUTH"
+    };
+
     private enum Mode {
         LINE,
         BLOCK,
@@ -49,6 +53,7 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
         LITERAL,
         LITERAL_DATA_BEGIN,
         LITERAL_DATA,
+        RESPONSE_TEXT,
         FAILED,
         CLOSED,
         COUNT
@@ -102,6 +107,7 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
     private Geary.Memory.GrowableBuffer? block_buffer = null;
     private unowned uint8[]? current_buffer = null;
     private int ins_priority = Priority.DEFAULT;
+
     private bool is_parsing_flags = false;
 
 
@@ -179,12 +185,12 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
             new Geary.State.Mapping(State.START_PARAM, Event.ERROR, on_error),
 
             new Geary.State.Mapping(State.ATOM, Event.CHAR, on_atom_char),
-            new Geary.State.Mapping(State.ATOM, Event.EOL, on_atom_eol),
+            new Geary.State.Mapping(State.ATOM, Event.EOL, on_param_eol),
             new Geary.State.Mapping(State.ATOM, Event.EOS, on_eos),
             new Geary.State.Mapping(State.ATOM, Event.ERROR, on_error),
 
             new Geary.State.Mapping(State.FLAG, Event.CHAR, on_flag_char),
-            new Geary.State.Mapping(State.FLAG, Event.EOL, on_atom_eol),
+            new Geary.State.Mapping(State.FLAG, Event.EOL, on_param_eol),
             new Geary.State.Mapping(State.FLAG, Event.EOS, on_eos),
             new Geary.State.Mapping(State.FLAG, Event.ERROR, on_error),
 
@@ -217,6 +223,11 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
             new Geary.State.Mapping(State.LITERAL_DATA, Event.EOS, on_eos),
             new Geary.State.Mapping(State.LITERAL_DATA, Event.ERROR, on_error),
 
+            new Geary.State.Mapping(State.RESPONSE_TEXT, Event.CHAR, on_response_text_char),
+            new Geary.State.Mapping(State.RESPONSE_TEXT, Event.EOL, on_param_eol),
+            new Geary.State.Mapping(State.RESPONSE_TEXT, Event.EOS, on_eos),
+            new Geary.State.Mapping(State.RESPONSE_TEXT, Event.ERROR, on_error),
+
             new Geary.State.Mapping(State.FAILED, Event.EOL, on_failed_eol),
             new Geary.State.Mapping(State.FAILED, Event.EOS, Geary.State.nop),
             new Geary.State.Mapping(State.FAILED, Event.ERROR, Geary.State.nop),
@@ -590,7 +601,12 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
                 return State.START_PARAM;
 
             default:
-                if (!this.is_parsing_flags) {
+                if (this.context_stack.size == 1 &&
+                    this.context.size >= 2 &&
+                    this.context.get(1).to_string().ascii_up() in RESPONSE_ATOMS) {
+                    append_to_string(ch);
+                    return State.RESPONSE_TEXT;
+                } else if (!this.is_parsing_flags) {
                     if (DataFormat.is_atom_special(ch)) {
                         warning("Received an invalid atom-char: %c", ch);
                         return State.FAILED;
@@ -697,7 +713,7 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
         return State.TAG;
     }
 
-    private uint on_atom_eol(uint state, uint event, void *user) {
+    private uint on_param_eol(uint state, uint event, void *user) {
         // clean up final atom
         save_string_parameter(false);
         flush_params();
@@ -837,6 +853,12 @@ public class Geary.Imap.Deserializer : BaseObject, Logging.Source {
         return State.START_PARAM;
     }
 
+    private uint on_response_text_char(uint state, uint event, void *user) {
+        char ch = *((char *) user);
+        append_to_string(ch);
+        return State.RESPONSE_TEXT;
+    }
+
     private uint on_eos() {
         debug("EOS");
 
diff --git a/test/engine/imap/transport/imap-deserializer-test.vala 
b/test/engine/imap/transport/imap-deserializer-test.vala
index 2f3a2d4a..b3a61712 100644
--- a/test/engine/imap/transport/imap-deserializer-test.vala
+++ b/test/engine/imap/transport/imap-deserializer-test.vala
@@ -47,6 +47,9 @@ class Geary.Imap.DeserializerTest : TestCase {
         // fail, disable for the moment
         add_test("invalid_flag_prefix", invalid_flag_prefix);
 
+        add_test("reserved_in_response_text", reserved_in_response_text);
+
+
         add_test("instant_eos", instant_eos);
         add_test("bye_eos", bye_eos);
     }
@@ -220,14 +223,13 @@ class Geary.Imap.DeserializerTest : TestCase {
 
     public void aliyun_greeting() throws Error {
         string greeting = "* OK AliYun IMAP Server Ready(10.147.40.164)";
-        string parsed = "* OK AliYun IMAP Server Ready (10.147.40.164)";
         this.stream.add_data(greeting.data);
         this.stream.add_data(EOL.data);
 
         this.process.begin(Expect.MESSAGE, this.async_completion);
         RootParameters? message = this.process.end(async_result());
 
-        assert(message.to_string() == parsed);
+        assert(message.to_string() == greeting);
     }
 
     public void invalid_atom_prefix() throws Error {
@@ -320,6 +322,18 @@ class Geary.Imap.DeserializerTest : TestCase {
         //this.process.end(async_result());
     }
 
+    public void reserved_in_response_text() throws Error {
+        // As seen in #711
+        string line = """a008 BAD Missing ] in: header.fields""";
+        this.stream.add_data(line.data);
+        this.stream.add_data(EOL.data);
+
+        this.process.begin(Expect.MESSAGE, this.async_completion);
+        RootParameters? message = this.process.end(async_result());
+
+        assert(message.to_string() == line);
+    }
+
     public void instant_eos() throws Error {
         this.process.begin(Expect.EOS, this.async_completion);
         this.process.end(async_result());


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