Skip to content

Commit

Permalink
Added support for rfc8970 (IMAP4 Extension: Message Preview Generation)
Browse files Browse the repository at this point in the history
  • Loading branch information
jstedfast committed Feb 16, 2023
1 parent bef1059 commit c6967ce
Show file tree
Hide file tree
Showing 15 changed files with 835 additions and 21 deletions.
12 changes: 12 additions & 0 deletions MailKit/FetchRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,17 @@ public FetchRequest (MessageSummaryItems items, IEnumerable<string> headers) : t
/// </remarks>
/// <value>The set of headers to be fetched.</value>
public HeaderSet Headers { get; set; }

#if ENABLE_LAZY_PREVIEW_API
/// <summary>
/// Get or set options to use when fetching <see cref="MessageSummaryItems.PreviewText"/>.
/// </summary>
/// <remarks>
/// <para>Gets or sets options to use when fetching <see cref="MessageSummaryItems.PreviewText"/>.</para>
/// <note type="note">These options are only used if <see cref="Items"/> includes the
/// <see cref="MessageSummaryItems.PreviewText"/> value.</note>
/// </remarks>
public PreviewOptions PreviewOptions { get; set; }
#endif
}
}
12 changes: 12 additions & 0 deletions MailKit/IFetchRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,17 @@ public interface IFetchRequest
/// </remarks>
/// <value>The set of headers to be fetched.</value>
HeaderSet Headers { get; }

#if ENABLE_LAZY_PREVIEW_API
/// <summary>
/// Get the options to use when fetching <see cref="MessageSummaryItems.PreviewText"/>.
/// </summary>
/// <remarks>
/// <para>Gets the options to use when fetching <see cref="MessageSummaryItems.PreviewText"/>.</para>
/// <note type="note">These options are only used if <see cref="Items"/> includes the
/// <see cref="MessageSummaryItems.PreviewText"/> value.</note>
/// </remarks>
PreviewOptions PreviewOptions { get; }
#endif
}
}
1 change: 1 addition & 0 deletions MailKit/MailKit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@
<Compile Include="MetadataTag.cs" />
<Compile Include="ModSeqChangedEventArgs.cs" />
<Compile Include="NullProtocolLogger.cs" />
<Compile Include="PreviewOptions.cs" />
<Compile Include="ProgressStream.cs" />
<Compile Include="ProtocolException.cs" />
<Compile Include="ProtocolLogger.cs" />
Expand Down
1 change: 1 addition & 0 deletions MailKit/MailKitLite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@
<Compile Include="MetadataTag.cs" />
<Compile Include="ModSeqChangedEventArgs.cs" />
<Compile Include="NullProtocolLogger.cs" />
<Compile Include="PreviewOptions.cs" />
<Compile Include="ProgressStream.cs" />
<Compile Include="ProtocolException.cs" />
<Compile Include="ProtocolLogger.cs" />
Expand Down
5 changes: 5 additions & 0 deletions MailKit/Net/Imap/ImapCapabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,11 @@ public enum ImapCapabilities : ulong {
/// </summary>
SaveDate = 1L << 57,

/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc8970">PREVIEW</a> extension.
/// </summary>
Preview = 1L << 58,

#region GMail Extensions

/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions MailKit/Net/Imap/ImapEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,8 @@ void ProcessCapabilityToken (string atom)
Capabilities |= ImapCapabilities.Replace;
} else if (atom.Equals ("SAVEDATE", StringComparison.OrdinalIgnoreCase)) {
Capabilities |= ImapCapabilities.SaveDate;
} else if (atom.Equals ("PREVIEW", StringComparison.OrdinalIgnoreCase)) {
Capabilities |= ImapCapabilities.Preview;
} else if (atom.Equals ("XLIST", StringComparison.OrdinalIgnoreCase)) {
Capabilities |= ImapCapabilities.XList;
} else if (atom.Equals ("X-GM-EXT-1", StringComparison.OrdinalIgnoreCase)) {
Expand Down
35 changes: 27 additions & 8 deletions MailKit/Net/Imap/ImapFolderFetch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ void FetchSummaryItems (ImapEngine engine, MessageSummary message, FetchSummaryI
message.InternalDate = ReadDateTimeOffsetToken (engine, atom, cancellationToken);
message.Fields |= MessageSummaryItems.InternalDate;
} else if (atom.Equals ("SAVEDATE", StringComparison.OrdinalIgnoreCase)) {
message.SaveDate = ReadDateTimeOffsetToken (engine, atom, cancellationToken) ;
message.SaveDate = ReadDateTimeOffsetToken (engine, atom, cancellationToken);
message.Fields |= MessageSummaryItems.SaveDate;
} else if (atom.Equals ("RFC822.SIZE", StringComparison.OrdinalIgnoreCase)) {
token = engine.ReadToken (cancellationToken);
Expand Down Expand Up @@ -449,6 +449,10 @@ void FetchSummaryItems (ImapEngine engine, MessageSummary message, FetchSummaryI
} else if (atom.Equals ("ANNOTATION", StringComparison.OrdinalIgnoreCase)) {
message.Annotations = ImapUtils.ParseAnnotationsAsync (engine, false, cancellationToken).GetAwaiter ().GetResult ();
message.Fields |= MessageSummaryItems.Annotations;
} else if (atom.Equals ("PREVIEW", StringComparison.OrdinalIgnoreCase)) {
format = string.Format (ImapEngine.GenericItemSyntaxErrorFormat, "PREVIEW", "{0}");
message.PreviewText = ImapUtils.ReadNStringToken (engine, format, false, cancellationToken);
message.Fields |= MessageSummaryItems.PreviewText;
} else {
// Unexpected or unknown token (such as XAOL.SPAM.REASON or XAOL-MSGID). Simply read 1 more token (the argument) and ignore.
token = engine.ReadToken (cancellationToken);
Expand Down Expand Up @@ -681,6 +685,10 @@ async Task FetchSummaryItemsAsync (ImapEngine engine, MessageSummary message, Fe
} else if (atom.Equals ("ANNOTATION", StringComparison.OrdinalIgnoreCase)) {
message.Annotations = await ImapUtils.ParseAnnotationsAsync (engine, true, cancellationToken).ConfigureAwait (false);
message.Fields |= MessageSummaryItems.Annotations;
} else if (atom.Equals ("PREVIEW", StringComparison.OrdinalIgnoreCase)) {
format = string.Format (ImapEngine.GenericItemSyntaxErrorFormat, "PREVIEW", "{0}");
message.PreviewText = await ImapUtils.ReadNStringTokenAsync (engine, format, false, cancellationToken).ConfigureAwait (false);
message.Fields |= MessageSummaryItems.PreviewText;
} else {
// Unexpected or unknown token (such as XAOL.SPAM.REASON or XAOL-MSGID). Simply read 1 more token (the argument) and ignore.
token = await engine.ReadTokenAsync (cancellationToken).ConfigureAwait (false);
Expand Down Expand Up @@ -722,10 +730,11 @@ internal static string FormatSummaryItems (ImapEngine engine, IFetchRequest requ
{
var items = request.Items;

if ((items & MessageSummaryItems.PreviewText) != 0) {
if ((engine.Capabilities & ImapCapabilities.Preview) == 0 && (items & MessageSummaryItems.PreviewText) != 0) {
// if the user wants the preview text, we will also need the UIDs and BODYSTRUCTUREs
// so that we can request a preview of the body text in subsequent FETCH requests.
items |= MessageSummaryItems.BodyStructure | MessageSummaryItems.UniqueId;
items &= ~MessageSummaryItems.PreviewText;
previewText = true;
} else {
previewText = false;
Expand All @@ -737,16 +746,13 @@ internal static string FormatSummaryItems (ImapEngine engine, IFetchRequest requ
}

if (engine.QuirksMode != ImapQuirksMode.GMail && !isNotify) {
// first, eliminate the aliases...
var alias = items & ~MessageSummaryItems.PreviewText;

if (alias == MessageSummaryItems.All)
if (items == MessageSummaryItems.All)
return "ALL";

if (alias == MessageSummaryItems.Full)
if (items == MessageSummaryItems.Full)
return "FULL";

if (alias == MessageSummaryItems.Fast)
if (items == MessageSummaryItems.Fast)
return "FAST";
}

Expand Down Expand Up @@ -790,6 +796,19 @@ internal static string FormatSummaryItems (ImapEngine engine, IFetchRequest requ
tokens.Add ("SAVEDATE");
}

if ((engine.Capabilities & ImapCapabilities.Preview) != 0) {
if ((items & MessageSummaryItems.PreviewText) != 0) {
#if ENABLE_LAZY_PREVIEW_API
if (request.PreviewOptions == PreviewOptions.Lazy)
tokens.Add ("PREVIEW (LAZY)");
else
tokens.Add ("PREVIEW");
#else
tokens.Add ("PREVIEW");
#endif
}
}

if ((engine.Capabilities & ImapCapabilities.GMailExt1) != 0) {
// now for the GMail extension items
if ((items & MessageSummaryItems.GMailMessageId) != 0)
Expand Down
4 changes: 2 additions & 2 deletions MailKit/Net/Imap/ImapUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ internal static ValueTask<string> ReadStringTokenAsync (ImapEngine engine, strin
return new ValueTask<string> (value);
}

static string ReadNStringToken (ImapEngine engine, string format, bool rfc2047, CancellationToken cancellationToken)
internal static string ReadNStringToken (ImapEngine engine, string format, bool rfc2047, CancellationToken cancellationToken)
{
var token = engine.ReadToken (cancellationToken);
string value;
Expand All @@ -744,7 +744,7 @@ static string ReadNStringToken (ImapEngine engine, string format, bool rfc2047,
return value;
}

static async ValueTask<string> ReadNStringTokenAsync (ImapEngine engine, string format, bool rfc2047, CancellationToken cancellationToken)
internal static async ValueTask<string> ReadNStringTokenAsync (ImapEngine engine, string format, bool rfc2047, CancellationToken cancellationToken)
{
var token = await engine.ReadTokenAsync (cancellationToken).ConfigureAwait (false);
string value;
Expand Down
46 changes: 46 additions & 0 deletions MailKit/PreviewOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// PreviewOptions.cs
//
// Author: Jeffrey Stedfast <[email protected]>
//
// Copyright (c) 2013-2023 .NET Foundation and Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

namespace MailKit {
#if ENABLE_LAZY_PREVIEW_API

/// <summary>
/// A set of options for fetching the preview text for messages.
/// </summary>
public enum PreviewOptions
{
/// <summary>
/// No options specified.
/// </summary>
None,

/// <summary>
/// The preview text should only be fetched if the server has it intstantly available (cached).
/// </summary>
Lazy
}
#endif
}
1 change: 1 addition & 0 deletions RFCs.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,4 @@ MailKit implements the following IETF specifications:
* [8508](https://tools.ietf.org/html/rfc8508): IMAP REPLACE Extension (Updates rfc3501)
* [8514](https://tools.ietf.org/html/rfc8514): Internet Message Access Protocol (IMAP) - SAVEDATE Extension
* [8689](https://tools.ietf.org/html/rfc8689): SMTP Require TLS Option
* [8970](https://tools.ietf.org/html/rfc8970): IMAP4 Extension: Message Preview Generation
Loading

0 comments on commit c6967ce

Please sign in to comment.