diff --git a/ImapClient.cs b/ImapClient.cs index 2fa285c..b9b27bc 100644 --- a/ImapClient.cs +++ b/ImapClient.cs @@ -494,31 +494,77 @@ private string SendCommandGetResponse(string command, bool resolveLiterals = tru /// Set to true to resolve possible literals /// returned by the server (Refer to RFC 3501 Section 4.3 for details). /// A response string from the server - private string GetResponse(bool resolveLiterals = true) { + private string GetResponse(bool resolveLiterals = true) + { const int Newline = 10, CarriageReturn = 13; - using (var mem = new MemoryStream()) { - lock (readLock) { - while (true) { - byte b = (byte)stream.ReadByte(); - if (b == CarriageReturn) - continue; - if (b == Newline) { - string s = Encoding.ASCII.GetString(mem.ToArray()); - if (resolveLiterals) { - s = Regex.Replace(s, @"{(\d+)}$", m => { - return "\"" + GetData(Convert.ToInt32(m.Groups[1].Value)) + - "\"" + GetResponse(false); - }); + const int ConnectionCheckThreshold = 100000; + try + { + using (var mem = new MemoryStream()) + { + var bytesRemainingUntilNextConnectionCheck = ConnectionCheckThreshold; + + lock (readLock) + { + while (true) + { + bytesRemainingUntilNextConnectionCheck--; + + if (bytesRemainingUntilNextConnectionCheck == 0) + { + CheckConnection(); + bytesRemainingUntilNextConnectionCheck = ConnectionCheckThreshold; + } + + byte b = (byte)stream.ReadByte(); + if (b == CarriageReturn) + continue; + if (b == Newline) + { + string s = Encoding.ASCII.GetString(mem.ToArray()); + if (resolveLiterals) + { + s = Regex.Replace(s, @"{(\d+)}$", m => + { + return "\"" + GetData(Convert.ToInt32(m.Groups[1].Value)) + + "\"" + GetResponse(false); + }); + } + ts.TraceInformation("S -> " + s); + return s; } - ts.TraceInformation("S -> " + s); - return s; - } else - mem.WriteByte(b); + else + mem.WriteByte(b); + } } } } + catch (BadServerResponseException) + { + throw; + } + catch (Exception ex) + { + throw new BadServerResponseException("Error encountered during read; see inner exception for details", ex); + } } + /// + /// In the event that the SslStream is disconnected unceremoniously, it will continue to + /// return data from ReadByte() indefinitely. The below method should be called periodically + /// to check the health of the connection + /// + private void CheckConnection() + { + if (client.Client.Poll(0, SelectMode.SelectRead)) + { + var buffer = new byte[1]; + if (client.Client.Receive(buffer, SocketFlags.Peek) == 0) + throw new BadServerResponseException("Error encountered during read: not connected"); + } + } + + /// /// Reads the specified amount of bytes from the server. This /// method blocks until the specified amount of bytes has been