Skip to content

Instantly share code, notes, and snippets.

@jstedfast
Created August 29, 2014 22:40
Show Gist options
  • Save jstedfast/95343ca4e95e6c1d3525 to your computer and use it in GitHub Desktop.
Save jstedfast/95343ca4e95e6c1d3525 to your computer and use it in GitHub Desktop.
Atomically read the first token of a line when in the IDLE state
diff --git a/MailKit/Net/Imap/ImapCommand.cs b/MailKit/Net/Imap/ImapCommand.cs
index 3d9f2b6..f6d9160 100644
--- a/MailKit/Net/Imap/ImapCommand.cs
+++ b/MailKit/Net/Imap/ImapCommand.cs
@@ -500,7 +500,7 @@ namespace MailKit.Net.Imap {
try {
Engine.Stream.ReadTimeout = -1;
- token = Engine.ReadToken (idle.LinkedToken);
+ token = Engine.AtomicReadToken (idle.LinkedToken);
Engine.Stream.ReadTimeout = timeout;
} catch (OperationCanceledException) {
Engine.Stream.ReadTimeout = timeout;
diff --git a/MailKit/Net/Imap/ImapEngine.cs b/MailKit/Net/Imap/ImapEngine.cs
index e7c90e4..4b411c8 100644
--- a/MailKit/Net/Imap/ImapEngine.cs
+++ b/MailKit/Net/Imap/ImapEngine.cs
@@ -640,6 +640,28 @@ namespace MailKit.Net.Imap {
}
/// <summary>
+ /// Reads the next token atomically.
+ /// </summary>
+ /// <returns>The token.</returns>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <exception cref="System.InvalidOperationException">
+ /// The engine is not connected.
+ /// </exception>
+ /// <exception cref="System.OperationCanceledException">
+ /// The operation was canceled via the cancellation token.
+ /// </exception>
+ /// <exception cref="System.IO.IOException">
+ /// An I/O error occurred.
+ /// </exception>
+ /// <exception cref="ImapProtocolException">
+ /// An IMAP protocol error occurred.
+ /// </exception>
+ public ImapToken AtomicReadToken (CancellationToken cancellationToken)
+ {
+ return Stream.AtomicReadToken (cancellationToken);
+ }
+
+ /// <summary>
/// Peeks at the next token.
/// </summary>
/// <returns>The next token.</returns>
diff --git a/MailKit/Net/Imap/ImapStream.cs b/MailKit/Net/Imap/ImapStream.cs
index db1dc2c..f81a5dd 100644
--- a/MailKit/Net/Imap/ImapStream.cs
+++ b/MailKit/Net/Imap/ImapStream.cs
@@ -491,7 +491,7 @@ namespace MailKit.Net.Imap {
}
}
- unsafe string ReadAtomString (byte* inbuf, bool flag, string specials, CancellationToken cancellationToken)
+ unsafe string ReadAtomString (byte* inbuf, string specials, bool atomic, bool flag, CancellationToken cancellationToken)
{
var builder = new StringBuilder ();
byte* inptr = inbuf + inputIndex;
@@ -512,7 +512,10 @@ namespace MailKit.Net.Imap {
if (inptr < inend)
break;
- inputIndex = (int) (inptr - inbuf);
+ if (!atomic)
+ inputIndex = (int) (inptr - inbuf);
+ else
+ builder.Clear ();
ReadAhead (1, cancellationToken);
@@ -525,9 +528,9 @@ namespace MailKit.Net.Imap {
return builder.ToString ();
}
- unsafe ImapToken ReadAtomToken (byte* inbuf, string specials, CancellationToken cancellationToken)
+ unsafe ImapToken ReadAtomToken (byte* inbuf, string specials, bool atomic, CancellationToken cancellationToken)
{
- var atom = ReadAtomString (inbuf, false, specials, cancellationToken);
+ var atom = ReadAtomString (inbuf, specials, atomic, false, cancellationToken);
return atom == "NIL" ? new ImapToken (ImapTokenType.Nil, atom) : new ImapToken (ImapTokenType.Atom, atom);
}
@@ -536,7 +539,7 @@ namespace MailKit.Net.Imap {
{
inputIndex++;
- var flag = "\\" + ReadAtomString (inbuf, true, AtomSpecials, cancellationToken);
+ var flag = "\\" + ReadAtomString (inbuf, AtomSpecials, false, true, cancellationToken);
return new ImapToken (ImapTokenType.Flag, flag);
}
@@ -638,6 +641,7 @@ namespace MailKit.Net.Imap {
/// </summary>
/// <returns>The token.</returns>
/// <param name="specials">A list of characters that are not legal in bare string tokens.</param>
+ /// <param name="atomic"><value>true</value> if atom tokens should be read atomically; otherwise, <value>false</value>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
@@ -648,7 +652,7 @@ namespace MailKit.Net.Imap {
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
- public ImapToken ReadToken (string specials, CancellationToken cancellationToken)
+ public ImapToken ReadToken (string specials, bool atomic, CancellationToken cancellationToken)
{
CheckDisposed ();
@@ -696,7 +700,7 @@ namespace MailKit.Net.Imap {
return ReadFlagToken (inbuf, cancellationToken);
if (c != '+' && IsAtom (*inptr, specials))
- return ReadAtomToken (inbuf, specials, cancellationToken);
+ return ReadAtomToken (inbuf, specials, atomic, cancellationToken);
// special character token
inputIndex++;
@@ -710,6 +714,26 @@ namespace MailKit.Net.Imap {
/// Reads the next available token from the stream.
/// </summary>
/// <returns>The token.</returns>
+ /// <param name="specials">A list of characters that are not legal in bare string tokens.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <exception cref="System.ObjectDisposedException">
+ /// The stream has been disposed.
+ /// </exception>
+ /// <exception cref="System.OperationCanceledException">
+ /// The operation was canceled via the cancellation token.
+ /// </exception>
+ /// <exception cref="System.IO.IOException">
+ /// An I/O error occurred.
+ /// </exception>
+ public ImapToken ReadToken (string specials, CancellationToken cancellationToken)
+ {
+ return ReadToken (specials, false, cancellationToken);
+ }
+
+ /// <summary>
+ /// Reads the next available token from the stream.
+ /// </summary>
+ /// <returns>The token.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
@@ -722,7 +746,26 @@ namespace MailKit.Net.Imap {
/// </exception>
public ImapToken ReadToken (CancellationToken cancellationToken)
{
- return ReadToken (AtomSpecials, cancellationToken);
+ return ReadToken (AtomSpecials, false, cancellationToken);
+ }
+
+ /// <summary>
+ /// Reads the next available token from the stream atomically.
+ /// </summary>
+ /// <returns>The token.</returns>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <exception cref="System.ObjectDisposedException">
+ /// The stream has been disposed.
+ /// </exception>
+ /// <exception cref="System.OperationCanceledException">
+ /// The operation was canceled via the cancellation token.
+ /// </exception>
+ /// <exception cref="System.IO.IOException">
+ /// An I/O error occurred.
+ /// </exception>
+ public ImapToken AtomicReadToken (CancellationToken cancellationToken)
+ {
+ return ReadToken (AtomSpecials, true, cancellationToken);
}
/// <summary>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment