6771 lines
274 KiB
C#
6771 lines
274 KiB
C#
//
|
|
// ImapFolderFetch.cs
|
|
//
|
|
// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
|
|
//
|
|
// Copyright (c) 2013-2020 .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.
|
|
//
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Globalization;
|
|
using System.Threading.Tasks;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
|
|
using MimeKit;
|
|
using MimeKit.IO;
|
|
using MimeKit.Text;
|
|
using MimeKit.Utils;
|
|
|
|
using MailKit.Search;
|
|
|
|
namespace MailKit.Net.Imap
|
|
{
|
|
public partial class ImapFolder
|
|
{
|
|
internal static readonly HashSet<string> EmptyHeaderFields = new HashSet<string> ();
|
|
const int PreviewHtmlLength = 16 * 1024;
|
|
const int PreviewTextLength = 512;
|
|
|
|
class FetchSummaryContext
|
|
{
|
|
public readonly List<IMessageSummary> Messages;
|
|
|
|
public FetchSummaryContext ()
|
|
{
|
|
Messages = new List<IMessageSummary> ();
|
|
}
|
|
|
|
int BinarySearch (int index, bool insert)
|
|
{
|
|
int min = 0, max = Messages.Count;
|
|
|
|
if (max == 0)
|
|
return insert ? 0 : -1;
|
|
|
|
do {
|
|
int i = min + ((max - min) / 2);
|
|
|
|
if (index == Messages[i].Index)
|
|
return i;
|
|
|
|
if (index > Messages[i].Index) {
|
|
min = i + 1;
|
|
} else {
|
|
max = i;
|
|
}
|
|
} while (min < max);
|
|
|
|
return insert ? min : -1;
|
|
}
|
|
|
|
public void Add (int index, MessageSummary message)
|
|
{
|
|
int i = BinarySearch (index, true);
|
|
|
|
if (i < Messages.Count)
|
|
Messages.Insert (i, message);
|
|
else
|
|
Messages.Add (message);
|
|
}
|
|
|
|
public bool TryGetValue (int index, out MessageSummary message)
|
|
{
|
|
int i;
|
|
|
|
if ((i = BinarySearch (index, false)) == -1) {
|
|
message = null;
|
|
return false;
|
|
}
|
|
|
|
message = (MessageSummary) Messages[i];
|
|
|
|
return true;
|
|
}
|
|
|
|
public void OnMessageExpunged (object sender, MessageEventArgs args)
|
|
{
|
|
int index = BinarySearch (args.Index, true);
|
|
|
|
if (index >= Messages.Count)
|
|
return;
|
|
|
|
if (Messages[index].Index == args.Index)
|
|
Messages.RemoveAt (index);
|
|
|
|
for (int i = index; i < Messages.Count; i++) {
|
|
var message = (MessageSummary) Messages[i];
|
|
message.Index--;
|
|
}
|
|
}
|
|
}
|
|
|
|
static async Task ReadLiteralDataAsync (ImapEngine engine, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
var buf = new byte[4096];
|
|
int nread;
|
|
|
|
do {
|
|
if (doAsync)
|
|
nread = await engine.Stream.ReadAsync (buf, 0, buf.Length, cancellationToken).ConfigureAwait (false);
|
|
else
|
|
nread = engine.Stream.Read (buf, 0, buf.Length, cancellationToken);
|
|
} while (nread > 0);
|
|
}
|
|
|
|
static async Task SkipParenthesizedList (ImapEngine engine, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
do {
|
|
var token = await engine.PeekTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.Eoln)
|
|
return;
|
|
|
|
// token is safe to read, so pop it off the queue
|
|
await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.CloseParen)
|
|
break;
|
|
|
|
if (token.Type == ImapTokenType.OpenParen) {
|
|
// skip the inner parenthesized list
|
|
await SkipParenthesizedList (engine, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
async Task FetchSummaryItemsAsync (ImapEngine engine, MessageSummary message, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
var token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenParen, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
|
|
do {
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.CloseParen || token.Type == ImapTokenType.Eoln)
|
|
break;
|
|
|
|
bool parenthesized = false;
|
|
if (engine.QuirksMode == ImapQuirksMode.Domino && token.Type == ImapTokenType.OpenParen) {
|
|
// Note: Lotus Domino IMAP will (sometimes?) encapsulate the `ENVELOPE` segment of the
|
|
// response within an extra set of parenthesis.
|
|
//
|
|
// See https://github.com/jstedfast/MailKit/issues/943 for details.
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
parenthesized = true;
|
|
}
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.Atom, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
|
|
var atom = (string) token.Value;
|
|
string format;
|
|
ulong value64;
|
|
uint value;
|
|
int idx;
|
|
|
|
switch (atom.ToUpperInvariant ()) {
|
|
case "INTERNALDATE":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
switch (token.Type) {
|
|
case ImapTokenType.QString:
|
|
case ImapTokenType.Atom:
|
|
message.InternalDate = ImapUtils.ParseInternalDate ((string) token.Value);
|
|
break;
|
|
case ImapTokenType.Nil:
|
|
message.InternalDate = null;
|
|
break;
|
|
default:
|
|
throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
}
|
|
|
|
message.Fields |= MessageSummaryItems.InternalDate;
|
|
break;
|
|
case "RFC822.SIZE":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
message.Size = ImapEngine.ParseNumber (token, false, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
message.Fields |= MessageSummaryItems.Size;
|
|
break;
|
|
case "BODYSTRUCTURE":
|
|
format = string.Format (ImapEngine.GenericItemSyntaxErrorFormat, "BODYSTRUCTURE", "{0}");
|
|
message.Body = await ImapUtils.ParseBodyAsync (engine, format, string.Empty, doAsync, cancellationToken).ConfigureAwait (false);
|
|
message.Fields |= MessageSummaryItems.BodyStructure;
|
|
break;
|
|
case "BODY":
|
|
token = await engine.PeekTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
format = ImapEngine.FetchBodySyntaxErrorFormat;
|
|
|
|
if (token.Type == ImapTokenType.OpenBracket) {
|
|
var referencesField = false;
|
|
var headerFields = false;
|
|
|
|
// consume the '['
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenBracket, format, token);
|
|
|
|
// References and/or other headers were requested...
|
|
|
|
do {
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.CloseBracket)
|
|
break;
|
|
|
|
if (token.Type == ImapTokenType.OpenParen) {
|
|
do {
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.CloseParen)
|
|
break;
|
|
|
|
// the header field names will generally be atoms or qstrings but may also be literals
|
|
engine.Stream.UngetToken (token);
|
|
|
|
var field = await ImapUtils.ReadStringTokenAsync (engine, format, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (headerFields && !referencesField && field.Equals ("REFERENCES", StringComparison.OrdinalIgnoreCase))
|
|
referencesField = true;
|
|
} while (true);
|
|
} else {
|
|
ImapEngine.AssertToken (token, ImapTokenType.Atom, format, token);
|
|
|
|
atom = (string) token.Value;
|
|
|
|
headerFields = atom.Equals ("HEADER.FIELDS", StringComparison.OrdinalIgnoreCase);
|
|
|
|
if (!headerFields && atom.Equals ("HEADER", StringComparison.OrdinalIgnoreCase)) {
|
|
// if we're fetching *all* headers, then it will include the References header (if it exists)
|
|
referencesField = true;
|
|
}
|
|
}
|
|
} while (true);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseBracket, format, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.Literal, format, token);
|
|
|
|
try {
|
|
message.Headers = await engine.ParseHeadersAsync (engine.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
} catch (FormatException) {
|
|
message.Headers = new HeaderList ();
|
|
}
|
|
|
|
// consume any remaining literal data... (typically extra blank lines)
|
|
await ReadLiteralDataAsync (engine, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
message.References = new MessageIdList ();
|
|
|
|
if ((idx = message.Headers.IndexOf (HeaderId.References)) != -1) {
|
|
var references = message.Headers[idx];
|
|
var rawValue = references.RawValue;
|
|
|
|
foreach (var msgid in MimeUtils.EnumerateReferences (rawValue, 0, rawValue.Length))
|
|
message.References.Add (msgid);
|
|
}
|
|
|
|
message.Fields |= MessageSummaryItems.Headers;
|
|
|
|
if (referencesField)
|
|
message.Fields |= MessageSummaryItems.References;
|
|
} else {
|
|
message.Body = await ImapUtils.ParseBodyAsync (engine, format, string.Empty, doAsync, cancellationToken).ConfigureAwait (false);
|
|
message.Fields |= MessageSummaryItems.Body;
|
|
}
|
|
break;
|
|
case "ENVELOPE":
|
|
message.Envelope = await ImapUtils.ParseEnvelopeAsync (engine, doAsync, cancellationToken).ConfigureAwait (false);
|
|
message.Fields |= MessageSummaryItems.Envelope;
|
|
break;
|
|
case "FLAGS":
|
|
message.Flags = await ImapUtils.ParseFlagsListAsync (engine, atom, message.Keywords, doAsync, cancellationToken).ConfigureAwait (false);
|
|
message.Fields |= MessageSummaryItems.Flags;
|
|
break;
|
|
case "MODSEQ":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
value64 = ImapEngine.ParseNumber64 (token, false, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
message.Fields |= MessageSummaryItems.ModSeq;
|
|
message.ModSeq = value64;
|
|
|
|
if (value64 > HighestModSeq)
|
|
UpdateHighestModSeq (value64);
|
|
break;
|
|
case "UID":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
value = ImapEngine.ParseNumber (token, true, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
message.UniqueId = new UniqueId (UidValidity, value);
|
|
message.Fields |= MessageSummaryItems.UniqueId;
|
|
break;
|
|
case "EMAILID":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.Atom, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
message.Fields |= MessageSummaryItems.EmailId;
|
|
message.EmailId = (string) token.Value;
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
break;
|
|
case "THREADID":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.OpenParen) {
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.Atom, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
message.Fields |= MessageSummaryItems.ThreadId;
|
|
message.ThreadId = (string) token.Value;
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
} else {
|
|
ImapEngine.AssertToken (token, ImapTokenType.Nil, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
message.Fields |= MessageSummaryItems.ThreadId;
|
|
message.ThreadId = null;
|
|
}
|
|
break;
|
|
case "X-GM-MSGID":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
value64 = ImapEngine.ParseNumber64 (token, true, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
message.Fields |= MessageSummaryItems.GMailMessageId;
|
|
message.GMailMessageId = value64;
|
|
break;
|
|
case "X-GM-THRID":
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
value64 = ImapEngine.ParseNumber64 (token, true, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
message.Fields |= MessageSummaryItems.GMailThreadId;
|
|
message.GMailThreadId = value64;
|
|
break;
|
|
case "X-GM-LABELS":
|
|
message.GMailLabels = await ImapUtils.ParseLabelsListAsync (engine, doAsync, cancellationToken).ConfigureAwait (false);
|
|
message.Fields |= MessageSummaryItems.GMailLabels;
|
|
break;
|
|
case "ANNOTATION":
|
|
message.Annotations = await ImapUtils.ParseAnnotationsAsync (engine, doAsync, cancellationToken).ConfigureAwait (false);
|
|
message.Fields |= MessageSummaryItems.Annotations;
|
|
break;
|
|
default:
|
|
// 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 (doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.OpenParen)
|
|
await SkipParenthesizedList (engine, doAsync, cancellationToken).ConfigureAwait (false);
|
|
break;
|
|
}
|
|
|
|
if (parenthesized) {
|
|
// Note: This is the second half of the Lotus Domino IMAP server work-around.
|
|
token = await engine.ReadTokenAsync (doAsync, cancellationToken).ConfigureAwait (false);
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
}
|
|
} while (true);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
}
|
|
|
|
async Task FetchSummaryItemsAsync (ImapEngine engine, ImapCommand ic, int index, bool doAsync)
|
|
{
|
|
var ctx = (FetchSummaryContext) ic.UserData;
|
|
MessageSummary message;
|
|
|
|
if (!ctx.TryGetValue (index, out message)) {
|
|
message = new MessageSummary (this, index);
|
|
ctx.Add (index, message);
|
|
}
|
|
|
|
await FetchSummaryItemsAsync (engine, message, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
OnMessageSummaryFetched (message);
|
|
}
|
|
|
|
internal static string FormatSummaryItems (ImapEngine engine, ref MessageSummaryItems items, HashSet<string> headers, out bool previewText, bool isNotify = false)
|
|
{
|
|
if ((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;
|
|
previewText = true;
|
|
} else {
|
|
previewText = false;
|
|
}
|
|
|
|
if ((items & MessageSummaryItems.BodyStructure) != 0 && (items & MessageSummaryItems.Body) != 0) {
|
|
// don't query both the BODY and BODYSTRUCTURE, that's just dumb...
|
|
items &= ~MessageSummaryItems.Body;
|
|
}
|
|
|
|
if (engine.QuirksMode != ImapQuirksMode.GMail && !isNotify) {
|
|
// first, eliminate the aliases...
|
|
var alias = items & ~MessageSummaryItems.PreviewText;
|
|
|
|
if (alias == MessageSummaryItems.All)
|
|
return "ALL";
|
|
|
|
if (alias == MessageSummaryItems.Full)
|
|
return "FULL";
|
|
|
|
if (alias == MessageSummaryItems.Fast)
|
|
return "FAST";
|
|
}
|
|
|
|
var tokens = new List<string> ();
|
|
|
|
// now add on any additional summary items...
|
|
if ((items & MessageSummaryItems.UniqueId) != 0)
|
|
tokens.Add ("UID");
|
|
if ((items & MessageSummaryItems.Flags) != 0)
|
|
tokens.Add ("FLAGS");
|
|
if ((items & MessageSummaryItems.InternalDate) != 0)
|
|
tokens.Add ("INTERNALDATE");
|
|
if ((items & MessageSummaryItems.Size) != 0)
|
|
tokens.Add ("RFC822.SIZE");
|
|
if ((items & MessageSummaryItems.Envelope) != 0)
|
|
tokens.Add ("ENVELOPE");
|
|
if ((items & MessageSummaryItems.BodyStructure) != 0)
|
|
tokens.Add ("BODYSTRUCTURE");
|
|
if ((items & MessageSummaryItems.Body) != 0)
|
|
tokens.Add ("BODY");
|
|
|
|
if ((engine.Capabilities & ImapCapabilities.CondStore) != 0) {
|
|
if ((items & MessageSummaryItems.ModSeq) != 0)
|
|
tokens.Add ("MODSEQ");
|
|
}
|
|
|
|
if ((engine.Capabilities & ImapCapabilities.Annotate) != 0) {
|
|
if ((items & MessageSummaryItems.Annotations) != 0)
|
|
tokens.Add ("ANNOTATION (/* (value size))");
|
|
}
|
|
|
|
if ((engine.Capabilities & ImapCapabilities.ObjectID) != 0) {
|
|
if ((items & MessageSummaryItems.EmailId) != 0)
|
|
tokens.Add ("EMAILID");
|
|
if ((items & MessageSummaryItems.ThreadId) != 0)
|
|
tokens.Add ("THREADID");
|
|
}
|
|
|
|
if ((engine.Capabilities & ImapCapabilities.GMailExt1) != 0) {
|
|
// now for the GMail extension items
|
|
if ((items & MessageSummaryItems.GMailMessageId) != 0)
|
|
tokens.Add ("X-GM-MSGID");
|
|
if ((items & MessageSummaryItems.GMailThreadId) != 0)
|
|
tokens.Add ("X-GM-THRID");
|
|
if ((items & MessageSummaryItems.GMailLabels) != 0)
|
|
tokens.Add ("X-GM-LABELS");
|
|
}
|
|
|
|
if ((items & MessageSummaryItems.Headers) != 0) {
|
|
tokens.Add ("BODY.PEEK[HEADER]");
|
|
} else if ((items & MessageSummaryItems.References) != 0 || headers.Count > 0) {
|
|
var headerFields = new StringBuilder ("BODY.PEEK[HEADER.FIELDS (");
|
|
var references = false;
|
|
|
|
foreach (var header in headers) {
|
|
if (header.Equals ("REFERENCES", StringComparison.OrdinalIgnoreCase))
|
|
references = true;
|
|
|
|
headerFields.Append (header);
|
|
headerFields.Append (' ');
|
|
}
|
|
|
|
if ((items & MessageSummaryItems.References) != 0 && !references)
|
|
headerFields.Append ("REFERENCES ");
|
|
|
|
headerFields[headerFields.Length - 1] = ')';
|
|
headerFields.Append (']');
|
|
|
|
tokens.Add (headerFields.ToString ());
|
|
}
|
|
|
|
if (tokens.Count == 1 && !isNotify)
|
|
return tokens[0];
|
|
|
|
return string.Format ("({0})", string.Join (" ", tokens));
|
|
}
|
|
|
|
string FormatSummaryItems (ref MessageSummaryItems items, HashSet<string> headers, out bool previewText)
|
|
{
|
|
return FormatSummaryItems (Engine, ref items, headers, out previewText);
|
|
}
|
|
|
|
static IList<IMessageSummary> AsReadOnly (ICollection<IMessageSummary> collection)
|
|
{
|
|
var array = new IMessageSummary[collection.Count];
|
|
|
|
collection.CopyTo (array, 0);
|
|
|
|
return new ReadOnlyCollection<IMessageSummary> (array);
|
|
}
|
|
|
|
class FetchPreviewTextContext : FetchStreamContextBase
|
|
{
|
|
static readonly PlainTextPreviewer textPreviewer = new PlainTextPreviewer ();
|
|
static readonly HtmlTextPreviewer htmlPreviewer = new HtmlTextPreviewer ();
|
|
|
|
readonly FetchSummaryContext ctx;
|
|
readonly ImapFolder folder;
|
|
|
|
public FetchPreviewTextContext (ImapFolder folder, FetchSummaryContext ctx) : base (null)
|
|
{
|
|
this.folder = folder;
|
|
this.ctx = ctx;
|
|
}
|
|
|
|
public override Task AddAsync (Section section, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
MessageSummary message;
|
|
|
|
if (!ctx.TryGetValue (section.Index, out message))
|
|
return Complete;
|
|
|
|
var body = message.TextBody;
|
|
TextPreviewer previewer;
|
|
|
|
if (body == null) {
|
|
previewer = htmlPreviewer;
|
|
body = message.HtmlBody;
|
|
} else {
|
|
previewer = textPreviewer;
|
|
}
|
|
|
|
if (body == null)
|
|
return Complete;
|
|
|
|
var charset = body.ContentType.Charset ?? "utf-8";
|
|
ContentEncoding encoding;
|
|
|
|
if (!string.IsNullOrEmpty (body.ContentTransferEncoding))
|
|
MimeUtils.TryParse (body.ContentTransferEncoding, out encoding);
|
|
else
|
|
encoding = ContentEncoding.Default;
|
|
|
|
using (var memory = new MemoryStream ()) {
|
|
var content = new MimeContent (section.Stream, encoding);
|
|
|
|
content.DecodeTo (memory);
|
|
memory.Position = 0;
|
|
|
|
try {
|
|
message.PreviewText = previewer.GetPreviewText (memory, charset);
|
|
} catch (DecoderFallbackException) {
|
|
memory.Position = 0;
|
|
|
|
message.PreviewText = previewer.GetPreviewText (memory, ImapEngine.Latin1);
|
|
}
|
|
|
|
message.Fields |= MessageSummaryItems.PreviewText;
|
|
folder.OnMessageSummaryFetched (message);
|
|
}
|
|
|
|
return Complete;
|
|
}
|
|
|
|
public override Task SetUniqueIdAsync (int index, UniqueId uid, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
return Complete;
|
|
}
|
|
}
|
|
|
|
async Task FetchPreviewTextAsync (FetchSummaryContext sctx, Dictionary<string, UniqueIdSet> bodies, int octets, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
foreach (var pair in bodies) {
|
|
var uids = pair.Value;
|
|
string specifier;
|
|
|
|
if (!string.IsNullOrEmpty (pair.Key))
|
|
specifier = pair.Key;
|
|
else
|
|
specifier = "TEXT";
|
|
|
|
// TODO: if the IMAP server supports the CONVERT extension, we could possibly use the
|
|
// CONVERT command instead to decode *and* convert (html) into utf-8 plain text.
|
|
//
|
|
// e.g. "UID CONVERT {0} (\"text/plain\" (\"charset\" \"utf-8\")) BINARY[{1}]<0.{2}>\r\n"
|
|
//
|
|
// This would allow us to more accurately fetch X number of characters because we wouldn't
|
|
// need to guestimate accounting for base64/quoted-printable decoding.
|
|
|
|
var command = string.Format (CultureInfo.InvariantCulture, "UID FETCH {0} (BODY.PEEK[{1}]<0.{2}>)\r\n", uids, specifier, octets);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchPreviewTextContext (this, sctx);
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
}
|
|
}
|
|
|
|
async Task GetPreviewTextAsync (FetchSummaryContext sctx, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
var textBodies = new Dictionary<string, UniqueIdSet> ();
|
|
var htmlBodies = new Dictionary<string, UniqueIdSet> ();
|
|
|
|
foreach (var item in sctx.Messages) {
|
|
Dictionary<string, UniqueIdSet> bodies;
|
|
var message = (MessageSummary) item;
|
|
var body = message.TextBody;
|
|
UniqueIdSet uids;
|
|
|
|
if (body == null) {
|
|
body = message.HtmlBody;
|
|
bodies = htmlBodies;
|
|
} else {
|
|
bodies = textBodies;
|
|
}
|
|
|
|
if (body == null) {
|
|
message.Fields |= MessageSummaryItems.PreviewText;
|
|
message.PreviewText = string.Empty;
|
|
OnMessageSummaryFetched (message);
|
|
continue;
|
|
}
|
|
|
|
if (!bodies.TryGetValue (body.PartSpecifier, out uids)) {
|
|
uids = new UniqueIdSet (SortOrder.Ascending);
|
|
bodies.Add (body.PartSpecifier, uids);
|
|
}
|
|
|
|
uids.Add (message.UniqueId);
|
|
}
|
|
|
|
MessageExpunged += sctx.OnMessageExpunged;
|
|
|
|
try {
|
|
await FetchPreviewTextAsync (sctx, textBodies, PreviewTextLength, doAsync, cancellationToken).ConfigureAwait (false);
|
|
await FetchPreviewTextAsync (sctx, htmlBodies, PreviewHtmlLength, doAsync, cancellationToken).ConfigureAwait (false);
|
|
} finally {
|
|
MessageExpunged -= sctx.OnMessageExpunged;
|
|
}
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, MessageSummaryItems items, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (uids == null)
|
|
throw new ArgumentNullException (nameof (uids));
|
|
|
|
if (items == MessageSummaryItems.None)
|
|
throw new ArgumentOutOfRangeException (nameof (items));
|
|
|
|
CheckState (true, false);
|
|
|
|
if (uids.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var query = FormatSummaryItems (ref items, EmptyHeaderFields, out previewText);
|
|
var command = string.Format ("UID FETCH %s {0}\r\n", query);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
MessageExpunged += ctx.OnMessageExpunged;
|
|
|
|
try {
|
|
foreach (var ic in Engine.CreateCommands (cancellationToken, this, command, uids)) {
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
}
|
|
} finally {
|
|
MessageExpunged -= ctx.OnMessageExpunged;
|
|
}
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, MessageSummaryItems items, IEnumerable<string> headers, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (uids == null)
|
|
throw new ArgumentNullException (nameof (uids));
|
|
|
|
var headerFields = ImapUtils.GetUniqueHeaders (headers);
|
|
|
|
CheckState (true, false);
|
|
|
|
if (uids.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var query = FormatSummaryItems (ref items, headerFields, out previewText);
|
|
var command = string.Format ("UID FETCH %s {0}\r\n", query);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
MessageExpunged += ctx.OnMessageExpunged;
|
|
|
|
try {
|
|
foreach (var ic in Engine.CreateCommands (cancellationToken, this, command, uids)) {
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
}
|
|
} finally {
|
|
MessageExpunged -= ctx.OnMessageExpunged;
|
|
}
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (uids == null)
|
|
throw new ArgumentNullException (nameof (uids));
|
|
|
|
if (items == MessageSummaryItems.None)
|
|
throw new ArgumentOutOfRangeException (nameof (items));
|
|
|
|
if (!supportsModSeq)
|
|
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
|
|
|
|
CheckState (true, false);
|
|
|
|
if (uids.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var query = FormatSummaryItems (ref items, EmptyHeaderFields, out previewText);
|
|
var vanished = Engine.QResyncEnabled ? " VANISHED" : string.Empty;
|
|
var modseqValue = modseq.ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("UID FETCH %s {0} (CHANGEDSINCE {1}{2})\r\n", query, modseqValue, vanished);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
MessageExpunged += ctx.OnMessageExpunged;
|
|
|
|
try {
|
|
foreach (var ic in Engine.CreateCommands (cancellationToken, this, command, uids)) {
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
}
|
|
} finally {
|
|
MessageExpunged -= ctx.OnMessageExpunged;
|
|
}
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (uids == null)
|
|
throw new ArgumentNullException (nameof (uids));
|
|
|
|
var headerFields = ImapUtils.GetUniqueHeaders (headers);
|
|
|
|
if (!supportsModSeq)
|
|
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
|
|
|
|
CheckState (true, false);
|
|
|
|
if (uids.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var query = FormatSummaryItems (ref items, headerFields, out previewText);
|
|
var vanished = Engine.QResyncEnabled ? " VANISHED" : string.Empty;
|
|
var modseqValue = modseq.ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("UID FETCH %s {0} (CHANGEDSINCE {1}{2})\r\n", query, modseqValue, vanished);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
MessageExpunged += ctx.OnMessageExpunged;
|
|
|
|
try {
|
|
foreach (var ic in Engine.CreateCommands (cancellationToken, this, command, uids)) {
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
}
|
|
} finally {
|
|
MessageExpunged -= ctx.OnMessageExpunged;
|
|
}
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message UIDs.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
|
|
/// </example>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="uids"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<UniqueId> uids, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, items, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message UIDs.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
|
|
/// </example>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="uids"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, items, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message UIDs.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<UniqueId> uids, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return Fetch (uids, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message UIDs.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message UIDs.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="uids"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<UniqueId> uids, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, items, headers, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message UIDs.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="uids"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, items, headers, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message UIDs that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>If the IMAP server supports the QRESYNC extension and the application has
|
|
/// enabled this feature via <see cref="ImapClient.EnableQuickResync(CancellationToken)"/>,
|
|
/// then this method will emit <see cref="MailFolder.MessagesVanished"/> events for messages
|
|
/// that have vanished since the specified mod-sequence value.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="uids"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, modseq, items, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message UIDs that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>If the IMAP server supports the QRESYNC extension and the application has
|
|
/// enabled this feature via <see cref="ImapClient.EnableQuickResync(CancellationToken)"/>,
|
|
/// then this method will emit <see cref="MailFolder.MessagesVanished"/> events for messages
|
|
/// that have vanished since the specified mod-sequence value.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="uids"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, modseq, items, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message UIDs that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>If the IMAP server supports the QRESYNC extension and the application has
|
|
/// enabled this feature via <see cref="ImapClient.EnableQuickResync(CancellationToken)"/>,
|
|
/// then this method will emit <see cref="MailFolder.MessagesVanished"/> events for messages
|
|
/// that have vanished since the specified mod-sequence value.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return Fetch (uids, modseq, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message UIDs that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>If the IMAP server supports the QRESYNC extension and the application has
|
|
/// enabled this feature via <see cref="ImapClient.EnableQuickResync(CancellationToken)"/>,
|
|
/// then this method will emit <see cref="MailFolder.MessagesVanished"/> events for messages
|
|
/// that have vanished since the specified mod-sequence value.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, modseq, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message UIDs that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>If the IMAP server supports the QRESYNC extension and the application has
|
|
/// enabled this feature via <see cref="ImapClient.EnableQuickResync(CancellationToken)"/>,
|
|
/// then this method will emit <see cref="MailFolder.MessagesVanished"/> events for messages
|
|
/// that have vanished since the specified mod-sequence value.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="uids"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, modseq, items, headers, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message UIDs that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message UIDs that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>If the IMAP server supports the QRESYNC extension and the application has
|
|
/// enabled this feature via <see cref="ImapClient.EnableQuickResync(CancellationToken)"/>,
|
|
/// then this method will emit <see cref="MailFolder.MessagesVanished"/> events for messages
|
|
/// that have vanished since the specified mod-sequence value.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="uids">The UIDs.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="uids"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<UniqueId> uids, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (uids, modseq, items, headers, true, cancellationToken);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, MessageSummaryItems items, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (indexes == null)
|
|
throw new ArgumentNullException (nameof (indexes));
|
|
|
|
if (items == MessageSummaryItems.None)
|
|
throw new ArgumentOutOfRangeException (nameof (items));
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (indexes.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var set = ImapUtils.FormatIndexSet (indexes);
|
|
var query = FormatSummaryItems (ref items, EmptyHeaderFields, out previewText);
|
|
var command = string.Format ("FETCH {0} {1}\r\n", set, query);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, MessageSummaryItems items, IEnumerable<string> headers, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (indexes == null)
|
|
throw new ArgumentNullException (nameof (indexes));
|
|
|
|
var headerFields = ImapUtils.GetUniqueHeaders (headers);
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (indexes.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var set = ImapUtils.FormatIndexSet (indexes);
|
|
var query = FormatSummaryItems (ref items, headerFields, out previewText);
|
|
var command = string.Format ("FETCH {0} {1}\r\n", set, query);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, ulong modseq, MessageSummaryItems items, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (indexes == null)
|
|
throw new ArgumentNullException (nameof (indexes));
|
|
|
|
if (items == MessageSummaryItems.None)
|
|
throw new ArgumentOutOfRangeException (nameof (items));
|
|
|
|
if (!supportsModSeq)
|
|
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (indexes.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var set = ImapUtils.FormatIndexSet (indexes);
|
|
var query = FormatSummaryItems (ref items, EmptyHeaderFields, out previewText);
|
|
var modseqValue = modseq.ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} {1} (CHANGEDSINCE {2})\r\n", set, query, modseqValue);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (indexes == null)
|
|
throw new ArgumentNullException (nameof (indexes));
|
|
|
|
var headerFields = ImapUtils.GetUniqueHeaders (headers);
|
|
|
|
if (!supportsModSeq)
|
|
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (indexes.Count == 0)
|
|
return new IMessageSummary[0];
|
|
|
|
var set = ImapUtils.FormatIndexSet (indexes);
|
|
var query = FormatSummaryItems (ref items, headerFields, out previewText);
|
|
var modseqValue = modseq.ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} {1} (CHANGEDSINCE {2})\r\n", set, query, modseqValue);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message indexes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="indexes"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<int> indexes, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, items, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message indexes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="indexes"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, items, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message indexes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<int> indexes, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return Fetch (indexes, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message indexes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message indexes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="indexes"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<int> indexes, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, items, headers, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message indexes.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="indexes"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, items, headers, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message indexes that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="indexes"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<int> indexes, ulong modseq, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, modseq, items, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message indexes that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="indexes"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="items"/> is empty.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, ulong modseq, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, modseq, items, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message indexes that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<int> indexes, ulong modseq, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return Fetch (indexes, modseq, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message indexes that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, ulong modseq, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, modseq, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the specified message indexes that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="indexes"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (IList<int> indexes, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, modseq, items, headers, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the specified message indexes that have a
|
|
/// higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the specified message indexes that
|
|
/// have a higher mod-sequence value than the one specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="indexes">The indexes.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="headers"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <para>One or more of the <paramref name="indexes"/> is invalid.</para>
|
|
/// <para>-or-</para>
|
|
/// <para>One or more of the specified <paramref name="headers"/> is invalid.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (IList<int> indexes, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (indexes, modseq, items, headers, true, cancellationToken);
|
|
}
|
|
|
|
static string GetFetchRange (int min, int max)
|
|
{
|
|
var minValue = (min + 1).ToString (CultureInfo.InvariantCulture);
|
|
|
|
if (min == max)
|
|
return minValue;
|
|
|
|
var maxValue = max != -1 ? (max + 1).ToString (CultureInfo.InvariantCulture) : "*";
|
|
|
|
return string.Format (CultureInfo.InvariantCulture, "{0}:{1}", minValue, maxValue);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (int min, int max, MessageSummaryItems items, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (min < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (min));
|
|
|
|
if (max != -1 && max < min)
|
|
throw new ArgumentOutOfRangeException (nameof (max));
|
|
|
|
if (items == MessageSummaryItems.None)
|
|
throw new ArgumentOutOfRangeException (nameof (items));
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (min == Count)
|
|
return new IMessageSummary[0];
|
|
|
|
var query = FormatSummaryItems (ref items, EmptyHeaderFields, out previewText);
|
|
var command = string.Format ("FETCH {0} {1}\r\n", GetFetchRange (min, max), query);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (int min, int max, MessageSummaryItems items, IEnumerable<string> headers, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (min < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (min));
|
|
|
|
if (max != -1 && max < min)
|
|
throw new ArgumentOutOfRangeException (nameof (max));
|
|
|
|
var headerFields = ImapUtils.GetUniqueHeaders (headers);
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (min == Count)
|
|
return new IMessageSummary[0];
|
|
|
|
var query = FormatSummaryItems (ref items, headerFields, out previewText);
|
|
var command = string.Format ("FETCH {0} {1}\r\n", GetFetchRange (min, max), query);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (int min, int max, ulong modseq, MessageSummaryItems items, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (min < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (min));
|
|
|
|
if (max != -1 && max < min)
|
|
throw new ArgumentOutOfRangeException (nameof (max));
|
|
|
|
if (items == MessageSummaryItems.None)
|
|
throw new ArgumentOutOfRangeException (nameof (items));
|
|
|
|
if (!supportsModSeq)
|
|
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
var query = FormatSummaryItems (ref items, EmptyHeaderFields, out previewText);
|
|
var modseqValue = modseq.ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} {1} (CHANGEDSINCE {2})\r\n", GetFetchRange (min, max), query, modseqValue);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
async Task<IList<IMessageSummary>> FetchAsync (int min, int max, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool previewText;
|
|
|
|
if (min < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (min));
|
|
|
|
if (max != -1 && max < min)
|
|
throw new ArgumentOutOfRangeException (nameof (max));
|
|
|
|
var headerFields = ImapUtils.GetUniqueHeaders (headers);
|
|
|
|
if (!supportsModSeq)
|
|
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
var query = FormatSummaryItems (ref items, headerFields, out previewText);
|
|
var modseqValue = modseq.ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} {1} (CHANGEDSINCE {2})\r\n", GetFetchRange (min, max), query, modseqValue);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchSummaryContext ();
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchSummaryItemsAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (previewText)
|
|
await GetPreviewTextAsync (ctx, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
return AsReadOnly (ctx.Messages);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the messages between the two indexes, inclusive.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes, inclusive.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="items"/> is empty.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (int min, int max, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, items, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the messages between the two indexes, inclusive.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes, inclusive.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="items"/> is empty.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (int min, int max, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, items, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the messages between the two indexes, inclusive.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes, inclusive.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (int min, int max, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return Fetch (min, max, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the messages between the two indexes, inclusive.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes, inclusive.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (int min, int max, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the messages between the two indexes, inclusive.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes, inclusive.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the specified <paramref name="headers"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (int min, int max, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, items, headers, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the messages between the two indexes, inclusive.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes, inclusive.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the specified <paramref name="headers"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (int min, int max, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, items, headers, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the messages between the two indexes (inclusive)
|
|
/// that have a higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes (inclusive) that have a higher mod-sequence value than the one
|
|
/// specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="items"/> is empty.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (int min, int max, ulong modseq, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, modseq, items, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the messages between the two indexes (inclusive)
|
|
/// that have a higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes (inclusive) that have a higher mod-sequence value than the one
|
|
/// specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="items"/> is empty.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (int min, int max, ulong modseq, MessageSummaryItems items, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, modseq, items, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the messages between the two indexes (inclusive)
|
|
/// that have a higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes (inclusive) that have a higher mod-sequence value than the one
|
|
/// specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (int min, int max, ulong modseq, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return Fetch (min, max, modseq, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the messages between the two indexes (inclusive)
|
|
/// that have a higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes (inclusive) that have a higher mod-sequence value than the one
|
|
/// specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (int min, int max, ulong modseq, MessageSummaryItems items, IEnumerable<HeaderId> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, modseq, items, ImapUtils.GetUniqueHeaders (headers), cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fetches the message summaries for the messages between the two indexes (inclusive)
|
|
/// that have a higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes (inclusive) that have a higher mod-sequence value than the one
|
|
/// specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the specified <paramref name="headers"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override IList<IMessageSummary> Fetch (int min, int max, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, modseq, items, headers, false, cancellationToken).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously fetches the message summaries for the messages between the two indexes (inclusive)
|
|
/// that have a higher mod-sequence value than the one specified.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Fetches the message summaries for the messages between the two
|
|
/// indexes (inclusive) that have a higher mod-sequence value than the one
|
|
/// specified.</para>
|
|
/// <para>It should be noted that if another client has modified any message
|
|
/// in the folder, the IMAP server may choose to return information that was
|
|
/// not explicitly requested. It is therefore important to be prepared to
|
|
/// handle both additional fields on a <see cref="IMessageSummary"/> for
|
|
/// messages that were requested as well as summaries for messages that were
|
|
/// not requested at all.</para>
|
|
/// </remarks>
|
|
/// <returns>An enumeration of summaries for the requested messages.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="modseq">The mod-sequence value.</param>
|
|
/// <param name="items">The message summary items to fetch.</param>
|
|
/// <param name="headers">The desired header fields.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="headers"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the specified <paramref name="headers"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="System.NotSupportedException">
|
|
/// The <see cref="ImapFolder"/> does not support mod-sequences.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<IList<IMessageSummary>> FetchAsync (int min, int max, ulong modseq, MessageSummaryItems items, IEnumerable<string> headers, CancellationToken cancellationToken = default (CancellationToken))
|
|
{
|
|
return FetchAsync (min, max, modseq, items, headers, true, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a backing stream for use with the GetMessage, GetBodyPart, and GetStream methods.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Allows subclass implementations to override the type of stream
|
|
/// created for use with the GetMessage, GetBodyPart and GetStream methods.</para>
|
|
/// <para>This could be useful for subclass implementations that intend to implement
|
|
/// support for caching and/or for subclass implementations that want to use
|
|
/// temporary file streams instead of memory-based streams for larger amounts of
|
|
/// message data.</para>
|
|
/// <para>Subclasses that implement caching using this API should wait for
|
|
/// <see cref="CommitStream"/> before adding the stream to their cache.</para>
|
|
/// <para>Streams returned by this method SHOULD clean up any allocated resources
|
|
/// such as deleting temporary files from the file system.</para>
|
|
/// <note type="note">The <paramref name="uid"/> will not be available for the various
|
|
/// GetMessage(), GetBodyPart() and GetStream() methods that take a message index rather
|
|
/// than a <see cref="UniqueId"/>. It may also not be available if the IMAP server
|
|
/// response does not specify the <c>UID</c> value prior to sending the <c>literal-string</c>
|
|
/// token containing the message stream.</note>
|
|
/// </remarks>
|
|
/// <seealso cref="CommitStream"/>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The unique identifier of the message, if available.</param>
|
|
/// <param name="section">The section of the message that is being fetched.</param>
|
|
/// <param name="offset">The starting offset of the message section being fetched.</param>
|
|
/// <param name="length">The length of the stream being fetched, measured in bytes.</param>
|
|
protected virtual Stream CreateStream (UniqueId? uid, string section, int offset, int length)
|
|
{
|
|
if (length > 4096)
|
|
return new MemoryBlockStream ();
|
|
|
|
return new MemoryStream (length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Commit a stream returned by <see cref="CreateStream"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Commits a stream returned by <see cref="CreateStream"/>.</para>
|
|
/// <para>This method is called only after both the message data has successfully
|
|
/// been written to the stream returned by <see cref="CreateStream"/> and a
|
|
/// <see cref="UniqueId"/> has been obtained for the associated message.</para>
|
|
/// <para>For subclasses implementing caching, this method should be used for
|
|
/// committing the stream to their cache.</para>
|
|
/// <note type="note">Subclass implementations may take advantage of the fact that
|
|
/// <see cref="CommitStream"/> allows returning a new <see cref="System.IO.Stream"/>
|
|
/// reference if they move a file on the file system and wish to return a new
|
|
/// <see cref="System.IO.FileStream"/> based on the new path, for example.</note>
|
|
/// </remarks>
|
|
/// <seealso cref="CreateStream"/>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="stream">The stream.</param>
|
|
/// <param name="uid">The unique identifier of the message.</param>
|
|
/// <param name="section">The section of the message that the stream represents.</param>
|
|
/// <param name="offset">The starting offset of the message section.</param>
|
|
/// <param name="length">The length of the stream, measured in bytes.</param>
|
|
protected virtual Stream CommitStream (Stream stream, UniqueId uid, string section, int offset, int length)
|
|
{
|
|
return stream;
|
|
}
|
|
|
|
async Task<HeaderList> ParseHeadersAsync (Stream stream, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
try {
|
|
return await Engine.ParseHeadersAsync (stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
} finally {
|
|
stream.Dispose ();
|
|
}
|
|
}
|
|
|
|
async Task<MimeMessage> ParseMessageAsync (Stream stream, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
bool dispose = !(stream is MemoryStream || stream is MemoryBlockStream);
|
|
|
|
try {
|
|
return await Engine.ParseMessageAsync (stream, !dispose, doAsync, cancellationToken).ConfigureAwait (false);
|
|
} finally {
|
|
if (dispose)
|
|
stream.Dispose ();
|
|
}
|
|
}
|
|
|
|
async Task<MimeEntity> ParseEntityAsync (Stream stream, bool dispose, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
try {
|
|
return await Engine.ParseEntityAsync (stream, !dispose, doAsync, cancellationToken).ConfigureAwait (false);
|
|
} finally {
|
|
if (dispose)
|
|
stream.Dispose ();
|
|
}
|
|
}
|
|
|
|
class Section
|
|
{
|
|
public int Index;
|
|
public UniqueId? UniqueId;
|
|
public Stream Stream;
|
|
public string Name;
|
|
public int Offset;
|
|
public int Length;
|
|
|
|
public Section (Stream stream, int index, UniqueId? uid, string name, int offset, int length)
|
|
{
|
|
Stream = stream;
|
|
Offset = offset;
|
|
Length = length;
|
|
UniqueId = uid;
|
|
Index = index;
|
|
Name = name;
|
|
}
|
|
}
|
|
|
|
abstract class FetchStreamContextBase : IDisposable
|
|
{
|
|
protected static readonly Task Complete = Task.FromResult (true);
|
|
public readonly List<Section> Sections = new List<Section> ();
|
|
readonly ITransferProgress progress;
|
|
|
|
public FetchStreamContextBase (ITransferProgress progress)
|
|
{
|
|
this.progress = progress;
|
|
}
|
|
|
|
public abstract Task AddAsync (Section section, bool doAsync, CancellationToken cancellationToken);
|
|
|
|
public virtual bool Contains (int index, string specifier, out Section section)
|
|
{
|
|
section = null;
|
|
return false;
|
|
}
|
|
|
|
public abstract Task SetUniqueIdAsync (int index, UniqueId uid, bool doAsync, CancellationToken cancellationToken);
|
|
|
|
public void Report (long nread, long total)
|
|
{
|
|
if (progress == null)
|
|
return;
|
|
|
|
progress.Report (nread, total);
|
|
}
|
|
|
|
public void Dispose ()
|
|
{
|
|
for (int i = 0; i < Sections.Count; i++) {
|
|
var section = Sections[i];
|
|
|
|
try {
|
|
section.Stream.Dispose ();
|
|
} catch (IOException) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FetchStreamContext : FetchStreamContextBase
|
|
{
|
|
public FetchStreamContext (ITransferProgress progress) : base (progress)
|
|
{
|
|
}
|
|
|
|
public override Task AddAsync (Section section, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
Sections.Add (section);
|
|
return Complete;
|
|
}
|
|
|
|
public bool TryGetSection (UniqueId uid, string specifier, out Section section, bool remove = false)
|
|
{
|
|
for (int i = 0; i < Sections.Count; i++) {
|
|
var item = Sections[i];
|
|
|
|
if (!item.UniqueId.HasValue || item.UniqueId.Value != uid)
|
|
continue;
|
|
|
|
if (item.Name.Equals (specifier, StringComparison.OrdinalIgnoreCase)) {
|
|
if (remove)
|
|
Sections.RemoveAt (i);
|
|
|
|
section = item;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
section = null;
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool TryGetSection (int index, string specifier, out Section section, bool remove = false)
|
|
{
|
|
for (int i = 0; i < Sections.Count; i++) {
|
|
var item = Sections[i];
|
|
|
|
if (item.Index != index)
|
|
continue;
|
|
|
|
if (item.Name.Equals (specifier, StringComparison.OrdinalIgnoreCase)) {
|
|
if (remove)
|
|
Sections.RemoveAt (i);
|
|
|
|
section = item;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
section = null;
|
|
|
|
return false;
|
|
}
|
|
|
|
public override Task SetUniqueIdAsync (int index, UniqueId uid, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
for (int i = 0; i < Sections.Count; i++) {
|
|
if (Sections[i].Index == index)
|
|
Sections[i].UniqueId = uid;
|
|
}
|
|
|
|
return Complete;
|
|
}
|
|
}
|
|
|
|
async Task FetchStreamAsync (ImapEngine engine, ImapCommand ic, int index, bool doAsync)
|
|
{
|
|
var token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
var annotations = new AnnotationsChangedEventArgs (index);
|
|
var labels = new MessageLabelsChangedEventArgs (index);
|
|
var flags = new MessageFlagsChangedEventArgs (index);
|
|
var modSeq = new ModSeqChangedEventArgs (index);
|
|
var ctx = (FetchStreamContextBase) ic.UserData;
|
|
var sectionBuilder = new StringBuilder ();
|
|
bool annotationsChanged = false;
|
|
bool modSeqChanged = false;
|
|
bool labelsChanged = false;
|
|
bool flagsChanged = false;
|
|
var buf = new byte[4096];
|
|
long nread = 0, size = 0;
|
|
UniqueId? uid = null;
|
|
Section section;
|
|
Stream stream;
|
|
string name;
|
|
int n;
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenParen, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
|
|
do {
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.Eoln) {
|
|
// Note: Most likely the the message body was calculated to be 1 or 2 bytes too
|
|
// short (e.g. did not include the trailing <CRLF>) and that is the EOLN we just
|
|
// reached. Ignore it and continue as normal.
|
|
//
|
|
// See https://github.com/jstedfast/MailKit/issues/954 for details.
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
if (token.Type == ImapTokenType.CloseParen)
|
|
break;
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.Atom, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
|
|
var atom = (string) token.Value;
|
|
int offset = 0, length;
|
|
ulong modseq;
|
|
uint value;
|
|
|
|
switch (atom.ToUpperInvariant ()) {
|
|
case "BODY":
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenBracket, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
sectionBuilder.Clear ();
|
|
|
|
do {
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.CloseBracket)
|
|
break;
|
|
|
|
if (token.Type == ImapTokenType.OpenParen) {
|
|
sectionBuilder.Append (" (");
|
|
|
|
do {
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.CloseParen)
|
|
break;
|
|
|
|
// the header field names will generally be atoms or qstrings but may also be literals
|
|
switch (token.Type) {
|
|
case ImapTokenType.Literal:
|
|
sectionBuilder.Append (await engine.ReadLiteralAsync (doAsync, ic.CancellationToken).ConfigureAwait (false));
|
|
break;
|
|
case ImapTokenType.QString:
|
|
case ImapTokenType.Atom:
|
|
sectionBuilder.Append ((string) token.Value);
|
|
break;
|
|
default:
|
|
throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
}
|
|
|
|
sectionBuilder.Append (' ');
|
|
} while (true);
|
|
|
|
if (sectionBuilder[sectionBuilder.Length - 1] == ' ')
|
|
sectionBuilder.Length--;
|
|
|
|
sectionBuilder.Append (')');
|
|
} else {
|
|
ImapEngine.AssertToken (token, ImapTokenType.Atom, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
sectionBuilder.Append ((string) token.Value);
|
|
}
|
|
} while (true);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseBracket, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.Atom) {
|
|
// this might be a region ("<###>")
|
|
var expr = (string) token.Value;
|
|
|
|
if (expr.Length > 2 && expr[0] == '<' && expr[expr.Length - 1] == '>') {
|
|
var region = expr.Substring (1, expr.Length - 2);
|
|
|
|
int.TryParse (region, NumberStyles.None, CultureInfo.InvariantCulture, out offset);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
}
|
|
}
|
|
|
|
name = sectionBuilder.ToString ();
|
|
|
|
switch (token.Type) {
|
|
case ImapTokenType.Literal:
|
|
length = (int) token.Value;
|
|
size += length;
|
|
|
|
stream = CreateStream (uid, name, offset, length);
|
|
|
|
try {
|
|
do {
|
|
if (doAsync)
|
|
n = await engine.Stream.ReadAsync (buf, 0, buf.Length, ic.CancellationToken).ConfigureAwait (false);
|
|
else
|
|
n = engine.Stream.Read (buf, 0, buf.Length, ic.CancellationToken);
|
|
|
|
if (n > 0) {
|
|
stream.Write (buf, 0, n);
|
|
nread += n;
|
|
|
|
ctx.Report (nread, size);
|
|
} else {
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
stream.Position = 0;
|
|
} catch {
|
|
stream.Dispose ();
|
|
throw;
|
|
}
|
|
break;
|
|
case ImapTokenType.QString:
|
|
case ImapTokenType.Atom:
|
|
var buffer = Encoding.UTF8.GetBytes ((string) token.Value);
|
|
length = buffer.Length;
|
|
nread += length;
|
|
size += length;
|
|
|
|
stream = CreateStream (uid, name, offset, length);
|
|
|
|
try {
|
|
stream.Write (buffer, 0, length);
|
|
ctx.Report (nread, size);
|
|
stream.Position = 0;
|
|
} catch {
|
|
stream.Dispose ();
|
|
throw;
|
|
}
|
|
break;
|
|
case ImapTokenType.Nil:
|
|
stream = CreateStream (uid, name, offset, 0);
|
|
length = 0;
|
|
break;
|
|
default:
|
|
throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
}
|
|
|
|
if (uid.HasValue)
|
|
stream = CommitStream (stream, uid.Value, name, offset, length);
|
|
|
|
// prevent leaks in the (invalid) case where a section may be returned twice
|
|
if (ctx.Contains (index, name, out section))
|
|
section.Stream.Dispose ();
|
|
|
|
section = new Section (stream, index, uid, name, offset, length);
|
|
await ctx.AddAsync (section, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
break;
|
|
case "UID":
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
value = ImapEngine.ParseNumber (token, true, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
uid = new UniqueId (UidValidity, value);
|
|
|
|
await ctx.SetUniqueIdAsync (index, uid.Value, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
annotations.UniqueId = uid.Value;
|
|
modSeq.UniqueId = uid.Value;
|
|
labels.UniqueId = uid.Value;
|
|
flags.UniqueId = uid.Value;
|
|
break;
|
|
case "MODSEQ":
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.OpenParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
modseq = ImapEngine.ParseNumber64 (token, false, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
token = await engine.ReadTokenAsync (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
|
|
|
|
if (modseq > HighestModSeq)
|
|
UpdateHighestModSeq (modseq);
|
|
|
|
annotations.ModSeq = modseq;
|
|
modSeq.ModSeq = modseq;
|
|
labels.ModSeq = modseq;
|
|
flags.ModSeq = modseq;
|
|
modSeqChanged = true;
|
|
break;
|
|
case "FLAGS":
|
|
// even though we didn't request this piece of information, the IMAP server
|
|
// may send it if another client has recently modified the message flags.
|
|
flags.Flags = await ImapUtils.ParseFlagsListAsync (engine, atom, flags.Keywords, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
flagsChanged = true;
|
|
break;
|
|
case "X-GM-LABELS":
|
|
// even though we didn't request this piece of information, the IMAP server
|
|
// may send it if another client has recently modified the message labels.
|
|
labels.Labels = await ImapUtils.ParseLabelsListAsync (engine, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
labelsChanged = true;
|
|
break;
|
|
case "ANNOTATION":
|
|
// even though we didn't request this piece of information, the IMAP server
|
|
// may send it if another client has recently modified the message annotations.
|
|
annotations.Annotations = await ImapUtils.ParseAnnotationsAsync (engine, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
annotationsChanged = true;
|
|
break;
|
|
default:
|
|
// 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 (doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
|
|
if (token.Type == ImapTokenType.OpenParen)
|
|
await SkipParenthesizedList (engine, doAsync, ic.CancellationToken).ConfigureAwait (false);
|
|
break;
|
|
}
|
|
} while (true);
|
|
|
|
ImapEngine.AssertToken (token, ImapTokenType.CloseParen, ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
|
|
|
|
if (flagsChanged)
|
|
OnMessageFlagsChanged (flags);
|
|
|
|
if (labelsChanged)
|
|
OnMessageLabelsChanged (labels);
|
|
|
|
if (annotationsChanged)
|
|
OnAnnotationsChanged (annotations);
|
|
|
|
if (modSeqChanged)
|
|
OnModSeqChanged (modSeq);
|
|
}
|
|
|
|
static string GetBodyPartQuery (string partSpec, bool headersOnly, out string[] tags)
|
|
{
|
|
string query;
|
|
|
|
if (headersOnly) {
|
|
tags = new string[1];
|
|
|
|
if (partSpec.Length > 0) {
|
|
query = string.Format ("BODY.PEEK[{0}.MIME]", partSpec);
|
|
tags[0] = partSpec + ".MIME";
|
|
} else {
|
|
query = "BODY.PEEK[HEADER]";
|
|
tags[0] = "HEADER";
|
|
}
|
|
} else {
|
|
tags = new string[2];
|
|
|
|
if (partSpec.Length > 0) {
|
|
tags[0] = partSpec + ".MIME";
|
|
tags[1] = partSpec;
|
|
} else {
|
|
tags[0] = "HEADER";
|
|
tags[1] = "TEXT";
|
|
}
|
|
|
|
query = string.Format ("BODY.PEEK[{0}] BODY.PEEK[{1}]", tags[0], tags[1]);
|
|
}
|
|
|
|
return query;
|
|
}
|
|
|
|
async Task<HeaderList> GetHeadersAsync (UniqueId uid, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
CheckState (true, false);
|
|
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, "UID FETCH %u (BODY.PEEK[HEADER])\r\n", uid.Id);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (uid, "HEADER", out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested message headers.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return await ParseHeadersAsync (section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
async Task<HeaderList> GetHeadersAsync (UniqueId uid, string partSpecifier, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (partSpecifier == null)
|
|
throw new ArgumentNullException (nameof (partSpecifier));
|
|
|
|
CheckState (true, false);
|
|
|
|
string[] tags;
|
|
|
|
var command = string.Format ("UID FETCH {0} ({1})\r\n", uid, GetBodyPartQuery (partSpecifier, true, out tags));
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (uid, tags[0], out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested body part headers.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return await ParseHeadersAsync (section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified message headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message headers.
|
|
/// </remarks>
|
|
/// <returns>The message headers.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override HeaderList GetHeaders (UniqueId uid, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (uid, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified message headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message headers.
|
|
/// </remarks>
|
|
/// <returns>The message headers.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<HeaderList> GetHeadersAsync (UniqueId uid, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (uid, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual HeaderList GetHeaders (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (uid, partSpecifier, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task<HeaderList> GetHeadersAsync (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (uid, partSpecifier, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override HeaderList GetHeaders (UniqueId uid, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetHeaders (uid, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<HeaderList> GetHeadersAsync (UniqueId uid, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetHeadersAsync (uid, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<HeaderList> GetHeadersAsync (int index, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
CheckState (true, false);
|
|
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, "FETCH %d (BODY.PEEK[HEADER])\r\n", index + 1);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (index, "HEADER", out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested message.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return await ParseHeadersAsync (section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
async Task<HeaderList> GetHeadersAsync (int index, string partSpecifier, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (partSpecifier == null)
|
|
throw new ArgumentNullException (nameof (partSpecifier));
|
|
|
|
CheckState (true, false);
|
|
|
|
string[] tags;
|
|
|
|
var seqid = (index + 1).ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} ({1})\r\n", seqid, GetBodyPartQuery (partSpecifier, true, out tags));
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (index, tags[0], out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested body part headers.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return await ParseHeadersAsync (section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified message headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message headers.
|
|
/// </remarks>
|
|
/// <returns>The message headers.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override HeaderList GetHeaders (int index, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (index, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified message headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message headers.
|
|
/// </remarks>
|
|
/// <returns>The message headers.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<HeaderList> GetHeadersAsync (int index, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (index, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual HeaderList GetHeaders (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (index, partSpecifier, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task<HeaderList> GetHeadersAsync (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetHeadersAsync (index, partSpecifier, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override HeaderList GetHeaders (int index, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetHeaders (index, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part headers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part headers.
|
|
/// </remarks>
|
|
/// <returns>The body part headers.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested body part headers.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<HeaderList> GetHeadersAsync (int index, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetHeadersAsync (index, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<MimeMessage> GetMessageAsync (UniqueId uid, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
CheckState (true, false);
|
|
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, "UID FETCH %u (BODY.PEEK[])\r\n", uid.Id);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (uid, string.Empty, out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested message.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return await ParseMessageAsync (section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message.
|
|
/// </remarks>
|
|
/// <returns>The message.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override MimeMessage GetMessage (UniqueId uid, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetMessageAsync (uid, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message.
|
|
/// </remarks>
|
|
/// <returns>The message.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<MimeMessage> GetMessageAsync (UniqueId uid, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetMessageAsync (uid, true, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<MimeMessage> GetMessageAsync (int index, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
CheckState (true, false);
|
|
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, "FETCH %d (BODY.PEEK[])\r\n", index + 1);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (index, string.Empty, out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested message.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return await ParseMessageAsync (section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message.
|
|
/// </remarks>
|
|
/// <returns>The message.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override MimeMessage GetMessage (int index, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetMessageAsync (index, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified message.
|
|
/// </remarks>
|
|
/// <returns>The message.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<MimeMessage> GetMessageAsync (int index, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetMessageAsync (index, true, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<MimeEntity> GetBodyPartAsync (UniqueId uid, string partSpecifier, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (partSpecifier == null)
|
|
throw new ArgumentNullException (nameof (partSpecifier));
|
|
|
|
CheckState (true, false);
|
|
|
|
string[] tags;
|
|
|
|
var command = string.Format ("UID FETCH {0} ({1})\r\n", uid, GetBodyPartQuery (partSpecifier, false, out tags));
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
ChainedStream chained = null;
|
|
bool dispose = false;
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
chained = new ChainedStream ();
|
|
|
|
foreach (var tag in tags) {
|
|
if (!ctx.TryGetSection (uid, tag, out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested body part.");
|
|
|
|
if (!(section.Stream is MemoryStream || section.Stream is MemoryBlockStream))
|
|
dispose = true;
|
|
|
|
chained.Add (section.Stream);
|
|
}
|
|
} catch {
|
|
if (chained != null)
|
|
chained.Dispose ();
|
|
|
|
throw;
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
var entity = await ParseEntityAsync (chained, dispose, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (partSpecifier.Length == 0) {
|
|
for (int i = entity.Headers.Count; i > 0; i--) {
|
|
var header = entity.Headers[i - 1];
|
|
|
|
if (!header.Field.StartsWith ("Content-", StringComparison.OrdinalIgnoreCase))
|
|
entity.Headers.RemoveAt (i - 1);
|
|
}
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message body.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual MimeEntity GetBodyPart (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetBodyPartAsync (uid, partSpecifier, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message body.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task<MimeEntity> GetBodyPartAsync (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetBodyPartAsync (uid, partSpecifier, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
|
|
/// </example>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message body.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override MimeEntity GetBodyPart (UniqueId uid, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetBodyPart (uid, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
|
|
/// </example>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message body.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<MimeEntity> GetBodyPartAsync (UniqueId uid, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetBodyPartAsync (uid, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<MimeEntity> GetBodyPartAsync (int index, string partSpecifier, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (partSpecifier == null)
|
|
throw new ArgumentNullException (nameof (partSpecifier));
|
|
|
|
CheckState (true, false);
|
|
|
|
string[] tags;
|
|
|
|
var seqid = (index + 1).ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} ({1})\r\n", seqid, GetBodyPartQuery (partSpecifier, false, out tags));
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
ChainedStream chained = null;
|
|
bool dispose = false;
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
chained = new ChainedStream ();
|
|
|
|
foreach (var tag in tags) {
|
|
if (!ctx.TryGetSection (index, tag, out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested body part.");
|
|
|
|
if (!(section.Stream is MemoryStream || section.Stream is MemoryBlockStream))
|
|
dispose = true;
|
|
|
|
chained.Add (section.Stream);
|
|
}
|
|
} catch {
|
|
if (chained != null)
|
|
chained.Dispose ();
|
|
|
|
throw;
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
var entity = await ParseEntityAsync (chained, dispose, doAsync, cancellationToken).ConfigureAwait (false);
|
|
|
|
if (partSpecifier.Length == 0) {
|
|
for (int i = entity.Headers.Count; i > 0; i--) {
|
|
var header = entity.Headers[i - 1];
|
|
|
|
if (!header.Field.StartsWith ("Content-", StringComparison.OrdinalIgnoreCase))
|
|
entity.Headers.RemoveAt (i - 1);
|
|
}
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual MimeEntity GetBodyPart (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetBodyPartAsync (index, partSpecifier, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="partSpecifier">The body part specifier.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="partSpecifier"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task<MimeEntity> GetBodyPartAsync (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetBodyPartAsync (index, partSpecifier, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override MimeEntity GetBodyPart (int index, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetBodyPart (index, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Gets the specified body part.
|
|
/// </remarks>
|
|
/// <returns>The body part.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="part">The body part.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="part"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<MimeEntity> GetBodyPartAsync (int index, BodyPart part, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (part == null)
|
|
throw new ArgumentNullException (nameof (part));
|
|
|
|
return GetBodyPartAsync (index, part.PartSpecifier, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<Stream> GetStreamAsync (UniqueId uid, int offset, int count, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (offset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (offset));
|
|
|
|
if (count < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (count));
|
|
|
|
CheckState (true, false);
|
|
|
|
if (count == 0)
|
|
return new MemoryStream ();
|
|
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, "UID FETCH %u (BODY.PEEK[]<%d.%d>)\r\n", uid.Id, offset, count);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (uid, string.Empty, out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested stream.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return section.Stream;
|
|
}
|
|
|
|
async Task<Stream> GetStreamAsync (int index, int offset, int count, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (offset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (offset));
|
|
|
|
if (count < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (count));
|
|
|
|
CheckState (true, false);
|
|
|
|
if (count == 0)
|
|
return new MemoryStream ();
|
|
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, "FETCH %d (BODY.PEEK[]<%d.%d>)\r\n", index + 1, offset, count);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section section;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (index, string.Empty, out section, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested stream.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return section.Stream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Fetches a substream of the message. If the starting offset is beyond
|
|
/// the end of the message, an empty stream is returned. If the number of
|
|
/// bytes desired extends beyond the end of the message, a truncated stream
|
|
/// will be returned.
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Stream GetStream (UniqueId uid, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (uid, offset, count, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously gets a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Fetches a substream of the message. If the starting offset is beyond
|
|
/// the end of the message, an empty stream is returned. If the number of
|
|
/// bytes desired extends beyond the end of the message, a truncated stream
|
|
/// will be returned.
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<Stream> GetStreamAsync (UniqueId uid, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (uid, offset, count, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Fetches a substream of the message. If the starting offset is beyond
|
|
/// the end of the message, an empty stream is returned. If the number of
|
|
/// bytes desired extends beyond the end of the message, a truncated stream
|
|
/// will be returned.
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="index"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Stream GetStream (int index, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (index, offset, count, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously gets a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Fetches a substream of the message. If the starting offset is beyond
|
|
/// the end of the message, an empty stream is returned. If the number of
|
|
/// bytes desired extends beyond the end of the message, a truncated stream
|
|
/// will be returned.
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="index"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<Stream> GetStreamAsync (int index, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (index, offset, count, true, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<Stream> GetStreamAsync (UniqueId uid, string section, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (section == null)
|
|
throw new ArgumentNullException (nameof (section));
|
|
|
|
CheckState (true, false);
|
|
|
|
var command = string.Format ("UID FETCH {0} (BODY.PEEK[{1}])\r\n", uid, section);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section s;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (uid, section, out s, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested stream.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return s.Stream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a substream of the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Stream GetStream (UniqueId uid, string section, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (uid, section, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously gets a substream of the specified body part.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<Stream> GetStreamAsync (UniqueId uid, string section, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (uid, section, true, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<Stream> GetStreamAsync (UniqueId uid, string section, int offset, int count, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (!uid.IsValid)
|
|
throw new ArgumentException ("The uid is invalid.", nameof (uid));
|
|
|
|
if (section == null)
|
|
throw new ArgumentNullException (nameof (section));
|
|
|
|
if (offset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (offset));
|
|
|
|
if (count < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (count));
|
|
|
|
CheckState (true, false);
|
|
|
|
if (count == 0)
|
|
return new MemoryStream ();
|
|
|
|
var range = string.Format (CultureInfo.InvariantCulture, "{0}.{1}", offset, count);
|
|
var command = string.Format ("UID FETCH {0} (BODY.PEEK[{1}]<{2}>)\r\n", uid, section, range);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section s;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (uid, section, out s, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested stream.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return s.Stream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message. If the starting offset is beyond
|
|
/// the end of the specified section of the message, an empty stream is returned. If
|
|
/// the number of bytes desired extends beyond the end of the section, a truncated
|
|
/// stream will be returned.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Stream GetStream (UniqueId uid, string section, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (uid, section, offset, count, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously gets a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message. If the starting offset is beyond
|
|
/// the end of the specified section of the message, an empty stream is returned. If
|
|
/// the number of bytes desired extends beyond the end of the section, a truncated
|
|
/// stream will be returned.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="uid">The UID of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// <paramref name="uid"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<Stream> GetStreamAsync (UniqueId uid, string section, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (uid, section, offset, count, true, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<Stream> GetStreamAsync (int index, string section, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (section == null)
|
|
throw new ArgumentNullException (nameof (section));
|
|
|
|
CheckState (true, false);
|
|
|
|
var seqid = (index + 1).ToString (CultureInfo.InvariantCulture);
|
|
var command = string.Format ("FETCH {0} (BODY.PEEK[{1}])\r\n", seqid, section);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section s;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (index, section, out s, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested stream.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return s.Stream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Stream GetStream (int index, string section, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (index, section, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously gets a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <paramref name="index"/> is out of range.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<Stream> GetStreamAsync (int index, string section, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (index, section, true, cancellationToken, progress);
|
|
}
|
|
|
|
async Task<Stream> GetStreamAsync (int index, string section, int offset, int count, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (index < 0 || index >= Count)
|
|
throw new ArgumentOutOfRangeException (nameof (index));
|
|
|
|
if (section == null)
|
|
throw new ArgumentNullException (nameof (section));
|
|
|
|
if (offset < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (offset));
|
|
|
|
if (count < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (count));
|
|
|
|
CheckState (true, false);
|
|
|
|
if (count == 0)
|
|
return new MemoryStream ();
|
|
|
|
var seqid = (index + 1).ToString (CultureInfo.InvariantCulture);
|
|
var range = string.Format (CultureInfo.InvariantCulture, "{0}.{1}", offset, count);
|
|
var command = string.Format ("FETCH {0} (BODY.PEEK[{1}]<{2}>)\r\n", seqid, section, range);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamContext (progress);
|
|
Section s;
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
|
|
if (!ctx.TryGetSection (index, section, out s, true))
|
|
throw new MessageNotFoundException ("The IMAP server did not return the requested stream.");
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
|
|
return s.Stream;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message. If the starting offset is beyond
|
|
/// the end of the specified section of the message, an empty stream is returned. If
|
|
/// the number of bytes desired extends beyond the end of the section, a truncated
|
|
/// stream will be returned.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="index"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Stream GetStream (int index, string section, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (index, section, offset, count, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously gets a substream of the specified message.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets a substream of the specified message. If the starting offset is beyond
|
|
/// the end of the specified section of the message, an empty stream is returned. If
|
|
/// the number of bytes desired extends beyond the end of the section, a truncated
|
|
/// stream will be returned.</para>
|
|
/// <para>For more information about how to construct the <paramref name="section"/>,
|
|
/// see Section 6.4.5 of RFC3501.</para>
|
|
/// </remarks>
|
|
/// <returns>The stream.</returns>
|
|
/// <param name="index">The index of the message.</param>
|
|
/// <param name="section">The desired section of the message.</param>
|
|
/// <param name="offset">The starting offset of the first desired byte.</param>
|
|
/// <param name="count">The number of bytes desired.</param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="section"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="index"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="offset"/> is negative.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="count"/> is negative.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </exception>
|
|
/// <exception cref="MessageNotFoundException">
|
|
/// The IMAP server did not return the requested message stream.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public override Task<Stream> GetStreamAsync (int index, string section, int offset, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamAsync (index, section, offset, count, true, cancellationToken, progress);
|
|
}
|
|
|
|
class FetchStreamCallbackContext : FetchStreamContextBase
|
|
{
|
|
readonly ImapFolder folder;
|
|
readonly object callback;
|
|
|
|
public FetchStreamCallbackContext (ImapFolder folder, object callback, ITransferProgress progress) : base (progress)
|
|
{
|
|
this.folder = folder;
|
|
this.callback = callback;
|
|
}
|
|
|
|
Task InvokeCallbackAsync (ImapFolder folder, int index, UniqueId uid, Stream stream, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
if (doAsync)
|
|
return ((ImapFetchStreamAsyncCallback) callback) (folder, index, uid, stream, cancellationToken);
|
|
|
|
((ImapFetchStreamCallback) callback) (folder, index, uid, stream);
|
|
return Complete;
|
|
}
|
|
|
|
public override async Task AddAsync (Section section, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
if (section.UniqueId.HasValue) {
|
|
await InvokeCallbackAsync (folder, section.Index, section.UniqueId.Value, section.Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
section.Stream.Dispose ();
|
|
} else {
|
|
Sections.Add (section);
|
|
}
|
|
}
|
|
|
|
public override async Task SetUniqueIdAsync (int index, UniqueId uid, bool doAsync, CancellationToken cancellationToken)
|
|
{
|
|
for (int i = 0; i < Sections.Count; i++) {
|
|
if (Sections[i].Index == index) {
|
|
await InvokeCallbackAsync (folder, index, uid, Sections[i].Stream, doAsync, cancellationToken).ConfigureAwait (false);
|
|
Sections[i].Stream.Dispose ();
|
|
Sections.RemoveAt (i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async Task GetStreamsAsync (IList<UniqueId> uids, object callback, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (uids == null)
|
|
throw new ArgumentNullException (nameof (uids));
|
|
|
|
if (callback == null)
|
|
throw new ArgumentNullException (nameof (callback));
|
|
|
|
CheckState (true, false);
|
|
|
|
if (uids.Count == 0)
|
|
return;
|
|
|
|
var ctx = new FetchStreamCallbackContext (this, callback, progress);
|
|
var command = "UID FETCH %s (BODY.PEEK[])\r\n";
|
|
|
|
try {
|
|
foreach (var ic in Engine.CreateCommands (cancellationToken, this, command, uids)) {
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
}
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
}
|
|
|
|
async Task GetStreamsAsync (IList<int> indexes, object callback, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (indexes == null)
|
|
throw new ArgumentNullException (nameof (indexes));
|
|
|
|
if (callback == null)
|
|
throw new ArgumentNullException (nameof (callback));
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (indexes.Count == 0)
|
|
return;
|
|
|
|
var set = ImapUtils.FormatIndexSet (indexes);
|
|
var command = string.Format ("FETCH {0} (UID BODY.PEEK[])\r\n", set);
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamCallbackContext (this, callback, progress);
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
}
|
|
|
|
async Task GetStreamsAsync (int min, int max, object callback, bool doAsync, CancellationToken cancellationToken, ITransferProgress progress)
|
|
{
|
|
if (min < 0)
|
|
throw new ArgumentOutOfRangeException (nameof (min));
|
|
|
|
if (max != -1 && max < min)
|
|
throw new ArgumentOutOfRangeException (nameof (max));
|
|
|
|
if (callback == null)
|
|
throw new ArgumentNullException (nameof (callback));
|
|
|
|
CheckState (true, false);
|
|
CheckAllowIndexes ();
|
|
|
|
if (min == Count)
|
|
return;
|
|
|
|
var command = string.Format ("FETCH {0} (UID BODY.PEEK[])\r\n", GetFetchRange (min, max));
|
|
var ic = new ImapCommand (Engine, cancellationToken, this, command);
|
|
var ctx = new FetchStreamCallbackContext (this, callback, progress);
|
|
|
|
ic.RegisterUntaggedHandler ("FETCH", FetchStreamAsync);
|
|
ic.UserData = ctx;
|
|
|
|
Engine.QueueCommand (ic);
|
|
|
|
try {
|
|
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
|
|
|
|
ProcessResponseCodes (ic, null);
|
|
|
|
if (ic.Response != ImapCommandResponse.Ok)
|
|
throw ImapCommandException.Create ("FETCH", ic);
|
|
} finally {
|
|
ctx.Dispose ();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the streams for the specified messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets the streams for the specified messages.</para>
|
|
/// </remarks>
|
|
/// <param name="uids">The uids of the messages.</param>
|
|
/// <param name="callback"></param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="callback"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual void GetStreams (IList<UniqueId> uids, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
GetStreamsAsync (uids, callback, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the streams for the specified messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Asynchronously gets the streams for the specified messages.</para>
|
|
/// </remarks>
|
|
/// <returns>An awaitable task.</returns>
|
|
/// <param name="uids">The uids of the messages.</param>
|
|
/// <param name="callback"></param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="uids"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="callback"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="uids"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task GetStreamsAsync (IList<UniqueId> uids, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamsAsync (uids, callback, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the streams for the specified messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets the streams for the specified messages.</para>
|
|
/// </remarks>
|
|
/// <param name="indexes">The indexes of the messages.</param>
|
|
/// <param name="callback"></param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="callback"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual void GetStreams (IList<int> indexes, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
GetStreamsAsync (indexes, callback, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the streams for the specified messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Asynchronously gets the streams for the specified messages.</para>
|
|
/// </remarks>
|
|
/// <returns>An awaitable task.</returns>
|
|
/// <param name="indexes">The indexes of the messages.</param>
|
|
/// <param name="callback"></param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <para><paramref name="indexes"/> is <c>null</c>.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="callback"/> is <c>null</c>.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentException">
|
|
/// One or more of the <paramref name="indexes"/> is invalid.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task GetStreamsAsync (IList<int> indexes, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamsAsync (indexes, callback, true, cancellationToken, progress);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the streams for the specified messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Gets the streams for the specified messages.</para>
|
|
/// </remarks>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="callback"></param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="callback"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual void GetStreams (int min, int max, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
GetStreamsAsync (min, max, callback, false, cancellationToken, progress).GetAwaiter ().GetResult ();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously get the streams for the specified messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>Asynchronously gets the streams for the specified messages.</para>
|
|
/// </remarks>
|
|
/// <returns>An awaitable task.</returns>
|
|
/// <param name="min">The minimum index.</param>
|
|
/// <param name="max">The maximum index, or <c>-1</c> to specify no upper bound.</param>
|
|
/// <param name="callback"></param>
|
|
/// <param name="cancellationToken">The cancellation token.</param>
|
|
/// <param name="progress">The progress reporting mechanism.</param>
|
|
/// <exception cref="System.ArgumentOutOfRangeException">
|
|
/// <para><paramref name="min"/> is out of range.</para>
|
|
/// <para>-or-</para>
|
|
/// <para><paramref name="max"/> is out of range.</para>
|
|
/// </exception>
|
|
/// <exception cref="System.ArgumentNullException">
|
|
/// <paramref name="callback"/> is <c>null</c>.
|
|
/// </exception>
|
|
/// <exception cref="System.ObjectDisposedException">
|
|
/// The <see cref="ImapClient"/> has been disposed.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotConnectedException">
|
|
/// The <see cref="ImapClient"/> is not connected.
|
|
/// </exception>
|
|
/// <exception cref="ServiceNotAuthenticatedException">
|
|
/// The <see cref="ImapClient"/> is not authenticated.
|
|
/// </exception>
|
|
/// <exception cref="FolderNotOpenException">
|
|
/// The <see cref="ImapFolder"/> is not currently open.
|
|
/// </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">
|
|
/// The server's response contained unexpected tokens.
|
|
/// </exception>
|
|
/// <exception cref="ImapCommandException">
|
|
/// The server replied with a NO or BAD response.
|
|
/// </exception>
|
|
public virtual Task GetStreamsAsync (int min, int max, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
|
|
{
|
|
return GetStreamsAsync (min, max, callback, true, cancellationToken, progress);
|
|
}
|
|
}
|
|
}
|