Skip to content

Commit

Permalink
minor refactoring to split out classes/enums
Browse files Browse the repository at this point in the history
  • Loading branch information
jstedfast committed Dec 30, 2024
1 parent 80dd317 commit a682950
Show file tree
Hide file tree
Showing 7 changed files with 412 additions and 313 deletions.
3 changes: 3 additions & 0 deletions MailKit/MailKit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<Compile Include="Net\Imap\ImapCommand.cs" />
<Compile Include="Net\Imap\ImapCommandException.cs" />
<Compile Include="Net\Imap\ImapCommandResponse.cs" />
<Compile Include="Net\Imap\ImapCommandStatus.cs" />
<Compile Include="Net\Imap\ImapEncoding.cs" />
<Compile Include="Net\Imap\ImapEngine.cs" />
<Compile Include="Net\Imap\ImapEventGroup.cs" />
Expand All @@ -87,7 +88,9 @@
<Compile Include="Net\Imap\ImapFolderFetch.cs" />
<Compile Include="Net\Imap\ImapFolderFlags.cs" />
<Compile Include="Net\Imap\ImapFolderSearch.cs" />
<Compile Include="Net\Imap\ImapIdleContext.cs" />
<Compile Include="Net\Imap\ImapImplementation.cs" />
<Compile Include="Net\Imap\ImapLiteral.cs" />
<Compile Include="Net\Imap\ImapProtocolException.cs" />
<Compile Include="Net\Imap\ImapResponseCode.cs" />
<Compile Include="Net\Imap\ImapSearchQueryOptimizer.cs" />
Expand Down
3 changes: 3 additions & 0 deletions MailKit/MailKitLite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<Compile Include="Net\Imap\ImapCommand.cs" />
<Compile Include="Net\Imap\ImapCommandException.cs" />
<Compile Include="Net\Imap\ImapCommandResponse.cs" />
<Compile Include="Net\Imap\ImapCommandStatus.cs" />
<Compile Include="Net\Imap\ImapEncoding.cs" />
<Compile Include="Net\Imap\ImapEngine.cs" />
<Compile Include="Net\Imap\ImapEventGroup.cs" />
Expand All @@ -92,7 +93,9 @@
<Compile Include="Net\Imap\ImapFolderFetch.cs" />
<Compile Include="Net\Imap\ImapFolderFlags.cs" />
<Compile Include="Net\Imap\ImapFolderSearch.cs" />
<Compile Include="Net\Imap\ImapIdleContext.cs" />
<Compile Include="Net\Imap\ImapImplementation.cs" />
<Compile Include="Net\Imap\ImapLiteral.cs" />
<Compile Include="Net\Imap\ImapProtocolException.cs" />
<Compile Include="Net\Imap\ImapResponseCode.cs" />
<Compile Include="Net\Imap\ImapSearchQueryOptimizer.cs" />
Expand Down
312 changes: 0 additions & 312 deletions MailKit/Net/Imap/ImapCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,13 @@
//

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Globalization;
using System.Threading.Tasks;
using System.Collections.Generic;

using MimeKit;
using MimeKit.IO;
using MimeKit.Utils;

using SslStream = MailKit.Net.SslStream;
Expand All @@ -60,323 +58,13 @@ namespace MailKit.Net.Imap {

delegate void ImapCommandResetHandler (ImapCommand ic);

/// <summary>
/// IMAP command status.
/// </summary>
enum ImapCommandStatus {
Created,
Queued,
Active,
Complete,
Error
}

enum ImapLiteralType {
String,
//Stream,
MimeMessage
}

enum ImapStringType {
Atom,
QString,
Literal,
Nil
}

/// <summary>
/// An IMAP IDLE context.
/// </summary>
/// <remarks>
/// <para>An IMAP IDLE command does not work like normal commands. Unlike most commands,
/// the IDLE command does not end until the client sends a separate "DONE" command.</para>
/// <para>In order to facilitate this, the way this works is that the consumer of MailKit's
/// IMAP APIs provides a 'doneToken' which signals to the command-processing loop to
/// send the "DONE" command. Since, like every other IMAP command, it is also necessary to
/// provide a means of cancelling the IDLE command, it becomes necessary to link the
/// 'doneToken' and the 'cancellationToken' together.</para>
/// </remarks>
sealed class ImapIdleContext : IDisposable
{
static readonly byte[] DoneCommand = Encoding.ASCII.GetBytes ("DONE\r\n");
CancellationTokenRegistration registration;

/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapIdleContext"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapIdleContext"/>.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="doneToken">The done token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public ImapIdleContext (ImapEngine engine, CancellationToken doneToken, CancellationToken cancellationToken)
{
CancellationToken = cancellationToken;
DoneToken = doneToken;
Engine = engine;
}

/// <summary>
/// Get the engine.
/// </summary>
/// <remarks>
/// Gets the engine.
/// </remarks>
/// <value>The engine.</value>
public ImapEngine Engine {
get; private set;
}

/// <summary>
/// Get the cancellation token.
/// </summary>
/// <remarks>
/// Get the cancellation token.
/// </remarks>
/// <value>The cancellation token.</value>
public CancellationToken CancellationToken {
get; private set;
}

/// <summary>
/// Get the done token.
/// </summary>
/// <remarks>
/// Gets the done token.
/// </remarks>
/// <value>The done token.</value>
public CancellationToken DoneToken {
get; private set;
}

#if false
/// <summary>
/// Get whether or not cancellation has been requested.
/// </summary>
/// <remarks>
/// Gets whether or not cancellation has been requested.
/// </remarks>
/// <value><c>true</c> if cancellation has been requested; otherwise, <c>false</c>.</value>
public bool IsCancellationRequested {
get { return CancellationToken.IsCancellationRequested; }
}

/// <summary>
/// Get whether or not the IDLE command should be ended.
/// </summary>
/// <remarks>
/// Gets whether or not the IDLE command should be ended.
/// </remarks>
/// <value><c>true</c> if the IDLE command should end; otherwise, <c>false</c>.</value>
public bool IsDoneRequested {
get { return DoneToken.IsCancellationRequested; }
}
#endif

void IdleComplete ()
{
if (Engine.State == ImapEngineState.Idle) {
try {
Engine.Stream.Write (DoneCommand, 0, DoneCommand.Length, CancellationToken);
Engine.Stream.Flush (CancellationToken);
} catch {
return;
}

Engine.State = ImapEngineState.Selected;
}
}

/// <summary>
/// Callback method to be used as the ImapCommand's ContinuationHandler.
/// </summary>
/// <remarks>
/// Callback method to be used as the ImapCommand's ContinuationHandler.
/// </remarks>
/// <param name="engine">The ImapEngine.</param>
/// <param name="ic">The ImapCommand.</param>
/// <param name="text">The text.</param>
/// <param name="doAsync"><c>true</c> if the command is being run asynchronously; otherwise, <c>false</c>.</param>
/// <returns></returns>
public Task ContinuationHandler (ImapEngine engine, ImapCommand ic, string text, bool doAsync)
{
Engine.State = ImapEngineState.Idle;

registration = DoneToken.Register (IdleComplete);

return Task.CompletedTask;
}

/// <summary>
/// Releases all resource used by the <see cref="MailKit.Net.Imap.ImapIdleContext"/> object.
/// </summary>
/// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="MailKit.Net.Imap.ImapIdleContext"/>. The
/// <see cref="Dispose"/> method leaves the <see cref="MailKit.Net.Imap.ImapIdleContext"/> in an unusable state. After
/// calling <see cref="Dispose"/>, you must release all references to the
/// <see cref="MailKit.Net.Imap.ImapIdleContext"/> so the garbage collector can reclaim the memory that the
/// <see cref="MailKit.Net.Imap.ImapIdleContext"/> was occupying.</remarks>
public void Dispose ()
{
registration.Dispose ();
}
}

/// <summary>
/// An IMAP literal object.
/// </summary>
/// <remarks>
/// The literal can be a string, byte[], Stream, or a MimeMessage.
/// </remarks>
class ImapLiteral
{
public readonly ImapLiteralType Type;
public readonly object Literal;
readonly FormatOptions format;
readonly Action<int> update;

/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>.
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="action">The progress update action.</param>
public ImapLiteral (FormatOptions options, MimeMessage message, Action<int> action = null)
{
format = options.Clone ();
format.NewLineFormat = NewLineFormat.Dos;

update = action;

Type = ImapLiteralType.MimeMessage;
Literal = message;
}

/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>.
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="literal">The literal.</param>
public ImapLiteral (FormatOptions options, byte[] literal)
{
format = options.Clone ();
format.NewLineFormat = NewLineFormat.Dos;

Type = ImapLiteralType.String;
Literal = literal;
}

/// <summary>
/// Get the length of the literal, in bytes.
/// </summary>
/// <remarks>
/// Gets the length of the literal, in bytes.
/// </remarks>
/// <value>The length.</value>
public long Length {
get {
if (Type == ImapLiteralType.String)
return ((byte[]) Literal).Length;

using (var measure = new MeasuringStream ()) {
//if (Type == ImapLiteralType.Stream) {
// var stream = (Stream) Literal;
// stream.CopyTo (measure, 4096);
// stream.Position = 0;

// return measure.Length;
//}

((MimeMessage) Literal).WriteTo (format, measure);

return measure.Length;
}
}
}

/// <summary>
/// Write the literal to the specified stream.
/// </summary>
/// <remarks>
/// Writes the literal to the specified stream.
/// </remarks>
/// <param name="stream">The stream.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public void WriteTo (ImapStream stream, CancellationToken cancellationToken)
{
if (Type == ImapLiteralType.String) {
var bytes = (byte[]) Literal;

stream.Write (bytes, 0, bytes.Length, cancellationToken);
stream.Flush (cancellationToken);
return;
}

//if (Type == ImapLiteralType.Stream) {
// var literal = (Stream) Literal;
// var buf = new byte[4096];
// int nread;

// while ((nread = literal.Read (buf, 0, buf.Length)) > 0)
// stream.Write (buf, 0, nread, cancellationToken);

// stream.Flush (cancellationToken);
// return;
//}

var message = (MimeMessage) Literal;

using (var s = new ProgressStream (stream, update)) {
message.WriteTo (format, s, cancellationToken);
s.Flush (cancellationToken);
}
}

/// <summary>
/// Asynchronously write the literal to the specified stream.
/// </summary>
/// <remarks>
/// Asynchronously writes the literal to the specified stream.
/// </remarks>
/// <param name="stream">The stream.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public async Task WriteToAsync (ImapStream stream, CancellationToken cancellationToken)
{
if (Type == ImapLiteralType.String) {
var bytes = (byte[]) Literal;

await stream.WriteAsync (bytes, 0, bytes.Length, cancellationToken).ConfigureAwait (false);
await stream.FlushAsync (cancellationToken).ConfigureAwait (false);
return;
}

//if (Type == ImapLiteralType.Stream) {
// var literal = (Stream) Literal;
// var buf = new byte[4096];
// int nread;

// while ((nread = await literal.ReadAsync (buf, 0, buf.Length, cancellationToken).ConfigureAwait (false)) > 0)
// await stream.WriteAsync (buf, 0, nread, cancellationToken).ConfigureAwait (false);

// await stream.FlushAsync (cancellationToken).ConfigureAwait (false);
// return;
//}

var message = (MimeMessage) Literal;

using (var s = new ProgressStream (stream, update)) {
await message.WriteToAsync (format, s, cancellationToken).ConfigureAwait (false);
await s.FlushAsync (cancellationToken).ConfigureAwait (false);
}
}
}

/// <summary>
/// A partial IMAP command.
/// </summary>
Expand Down
Loading

0 comments on commit a682950

Please sign in to comment.