add MailKit and MimeKit

master
Christopher 2020-06-30 08:21:49 +02:00
parent bff490f383
commit c7fdde81cd
434 changed files with 211308 additions and 0 deletions

View File

@ -0,0 +1,137 @@
//
// AccessControl.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.Collections.Generic;
namespace MailKit {
/// <summary>
/// An Access Control.
/// </summary>
/// <remarks>
/// An Access Control is a set of permissions available for a particular identity,
/// controlling whether or not that identity has the ability to perform various tasks.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
public class AccessControl
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessControl"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.AccessControl"/> with the given name and
/// access rights.
/// </remarks>
/// <param name="name">The identifier name.</param>
/// <param name="rights">The access rights.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="name"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="rights"/> is <c>null</c>.</para>
/// </exception>
public AccessControl (string name, IEnumerable<AccessRight> rights)
{
if (name == null)
throw new ArgumentNullException (nameof (name));
Rights = new AccessRights (rights);
Name = name;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessControl"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.AccessControl"/> with the given name and
/// access rights.
/// </remarks>
/// <param name="name">The identifier name.</param>
/// <param name="rights">The access rights.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="name"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="rights"/> is <c>null</c>.</para>
/// </exception>
public AccessControl (string name, string rights)
{
if (name == null)
throw new ArgumentNullException (nameof (name));
Rights = new AccessRights (rights);
Name = name;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessControl"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.AccessControl"/> with the given name and no
/// access rights.
/// </remarks>
/// <param name="name">The identifier name.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="name"/> is <c>null</c>.
/// </exception>
public AccessControl (string name)
{
if (name == null)
throw new ArgumentNullException (nameof (name));
Rights = new AccessRights ();
Name = name;
}
/// <summary>
/// The identifier name for the access control.
/// </summary>
/// <remarks>
/// The identifier name for the access control.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The identifier name.</value>
public string Name {
get; private set;
}
/// <summary>
/// Get the access rights.
/// </summary>
/// <remarks>
/// Gets the access rights.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The access rights.</value>
public AccessRights Rights {
get; private set;
}
}
}

View File

@ -0,0 +1,66 @@
//
// AccessControlList.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.Collections.Generic;
namespace MailKit {
/// <summary>
/// An Access Control List (ACL)
/// </summary>
/// <remarks>
/// An Access Control List (ACL) is a list of access controls defining the permissions
/// various identities have available.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
public class AccessControlList : List<AccessControl>
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessControlList"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.AccessControlList"/>.
/// </remarks>
/// <param name="controls">The list of access controls.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="controls"/> is <c>null</c>.
/// </exception>
public AccessControlList (IEnumerable<AccessControl> controls) : base (controls)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessControlList"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.AccessControlList"/>.
/// </remarks>
public AccessControlList ()
{
}
}
}

232
src/MailKit/AccessRight.cs Normal file
View File

@ -0,0 +1,232 @@
//
// AccessRight.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;
namespace MailKit {
/// <summary>
/// An individual Access Right to be used with ACLs.
/// </summary>
/// <remarks>
/// <para>An individual Access Right meant to be used with
/// <see cref="AccessControlList"/>.</para>
/// <para>For more information on what rights are available,
/// see https://tools.ietf.org/html/rfc4314#section-2.1
/// </para>
/// </remarks>
public struct AccessRight : IEquatable<AccessRight>
{
/// <summary>
/// The access right for folder lookups.
/// </summary>
/// <remarks>
/// Allows the <see cref="MailKit.IMailFolder"/> to be visible when listing folders.
/// </remarks>
public static readonly AccessRight LookupFolder = new AccessRight ('l');
/// <summary>
/// The access right for opening a folder and getting the status.
/// </summary>
/// <remarks>
/// Provides access for opening and getting the status of the folder.
/// </remarks>
public static readonly AccessRight OpenFolder = new AccessRight ('r');
/// <summary>
/// The access right for adding or removing the Seen flag on messages in the folder.
/// </summary>
/// <remarks>
/// Provides access to add or remove the <see cref="MessageFlags.Seen"/> flag on messages within the
/// <see cref="MailKit.IMailFolder"/>.
/// </remarks>
public static readonly AccessRight SetMessageSeen = new AccessRight ('s');
/// <summary>
/// The access right for adding or removing flags (other than Seen and Deleted)
/// on messages in a folder.
/// </summary>
/// <remarks>
/// Provides access to add or remove the <see cref="MessageFlags"/> on messages
/// (other than <see cref="MessageFlags.Seen"/> and
/// <see cref="MessageFlags.Deleted"/>) within the folder.
/// </remarks>
public static readonly AccessRight SetMessageFlags = new AccessRight ('w');
/// <summary>
/// The access right allowing messages to be appended or copied into the folder.
/// </summary>
/// <remarks>
/// Provides access to append or copy messages into the folder.
/// </remarks>
public static readonly AccessRight AppendMessages = new AccessRight ('i');
/// <summary>
/// The access right allowing subfolders to be created.
/// </summary>
/// <remarks>
/// Provides access to create subfolders.
/// </remarks>
public static readonly AccessRight CreateFolder = new AccessRight ('k');
/// <summary>
/// The access right for deleting a folder and/or its subfolders.
/// </summary>
/// <remarks>
/// Provides access to delete the folder and/or any subfolders.
/// </remarks>
public static readonly AccessRight DeleteFolder = new AccessRight ('x');
/// <summary>
/// The access right for adding or removing the Deleted flag to messages within a folder.
/// </summary>
/// <remarks>
/// Provides access to add or remove the <see cref="MessageFlags.Deleted"/> flag from
/// messages within the folder. It also provides access for setting the
/// <see cref="MessageFlags.Deleted"/> flag when appending a message to a folder.
/// </remarks>
public static readonly AccessRight SetMessageDeleted = new AccessRight ('t');
/// <summary>
/// The access right for expunging deleted messages in a folder.
/// </summary>
/// <remarks>
/// Provides access to expunge deleted messages in a folder.
/// </remarks>
public static readonly AccessRight ExpungeFolder = new AccessRight ('e');
/// <summary>
/// The access right for administering the ACLs of a folder.
/// </summary>
/// <remarks>
/// Provides administrative access to change the ACLs for the folder.
/// </remarks>
public static readonly AccessRight Administer = new AccessRight ('a');
/// <summary>
/// The character representing the particular access right.
/// </summary>
/// <remarks>
/// Represents the character value of the access right.
/// </remarks>
public readonly char Right;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessRight"/> struct.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.AccessRight"/> struct.
/// </remarks>
/// <param name="right">The access right.</param>
public AccessRight (char right)
{
Right = right;
}
#region IEquatable implementation
/// <summary>
/// Determines whether the specified <see cref="MailKit.AccessRight"/> is equal to the current <see cref="MailKit.AccessRight"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="MailKit.AccessRight"/> is equal to the current <see cref="MailKit.AccessRight"/>.
/// </remarks>
/// <param name="other">The <see cref="MailKit.AccessRight"/> to compare with the current <see cref="MailKit.AccessRight"/>.</param>
/// <returns><c>true</c> if the specified <see cref="MailKit.AccessRight"/> is equal to the current
/// <see cref="MailKit.AccessRight"/>; otherwise, <c>false</c>.</returns>
public bool Equals (AccessRight other)
{
return other.Right == Right;
}
#endregion
/// <summary>
/// Determines whether two access rights are equal.
/// </summary>
/// <remarks>
/// Determines whether two access rights are equal.
/// </remarks>
/// <returns><c>true</c> if <paramref name="right1"/> and <paramref name="right2"/> are equal; otherwise, <c>false</c>.</returns>
/// <param name="right1">The first access right to compare.</param>
/// <param name="right2">The second access right to compare.</param>
public static bool operator == (AccessRight right1, AccessRight right2)
{
return right1.Right == right2.Right;
}
/// <summary>
/// Determines whether two access rights are not equal.
/// </summary>
/// <remarks>
/// Determines whether two access rights are not equal.
/// </remarks>
/// <returns><c>true</c> if <paramref name="right1"/> and <paramref name="right2"/> are not equal; otherwise, <c>false</c>.</returns>
/// <param name="right1">The first access right to compare.</param>
/// <param name="right2">The second access right to compare.</param>
public static bool operator != (AccessRight right1, AccessRight right2)
{
return right1.Right != right2.Right;
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AccessRight"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AccessRight"/>.
/// </remarks>
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="MailKit.AccessRight"/>.</param>
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AccessRight"/>;
/// otherwise, <c>false</c>.</returns>
public override bool Equals (object obj)
{
return obj is AccessRight && ((AccessRight) obj).Right == Right;
}
/// <summary>
/// Serves as a hash function for a <see cref="MailKit.AccessRight"/> object.
/// </summary>
/// <remarks>
/// Serves as a hash function for a <see cref="MailKit.AccessRight"/> object.
/// </remarks>
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table.</returns>
public override int GetHashCode ()
{
return Right.GetHashCode ();
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AccessRight"/>.
/// </summary>
/// <remarks>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AccessRight"/>.
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.AccessRight"/>.</returns>
public override string ToString ()
{
return Right.ToString ();
}
}
}

317
src/MailKit/AccessRights.cs Normal file
View File

@ -0,0 +1,317 @@
//
// AccessRights.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.Collections;
using System.Collections.Generic;
namespace MailKit {
/// <summary>
/// A set of access rights.
/// </summary>
/// <remarks>
/// The set of access rights for a particular identity.
/// </remarks>
public class AccessRights : ICollection<AccessRight>
{
readonly List<AccessRight> list = new List<AccessRight> ();
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessRights"/> class.
/// </summary>
/// <remarks>
/// Creates a new set of access rights.
/// </remarks>
/// <param name="rights">The access rights.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="rights"/> is <c>null</c>.
/// </exception>
public AccessRights (IEnumerable<AccessRight> rights)
{
AddRange (rights);
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessRights"/> class.
/// </summary>
/// <remarks>
/// Creates a new set of access rights.
/// </remarks>
/// <param name="rights">The access rights.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="rights"/> is <c>null</c>.
/// </exception>
public AccessRights (string rights)
{
AddRange (rights);
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AccessRights"/> class.
/// </summary>
/// <remarks>
/// Creates an empty set of access rights.
/// </remarks>
public AccessRights ()
{
}
/// <summary>
/// Get the number of access rights in the collection.
/// </summary>
/// <remarks>
/// Gets the number of access rights in the collection.
/// </remarks>
/// <value>The count.</value>
public int Count {
get { return list.Count; }
}
/// <summary>
/// Get whether or not this set of access rights is read only.
/// </summary>
/// <remarks>
/// Gets whether or not this set of access rights is read only.
/// </remarks>
/// <value><c>true</c> if this collection is read only; otherwise, <c>false</c>.</value>
public bool IsReadOnly {
get { return false; }
}
/// <summary>
/// Add the specified access right.
/// </summary>
/// <remarks>
/// Adds the specified access right if it is not already included.
/// </remarks>
/// <param name="right">The access right.</param>
void ICollection<AccessRight>.Add (AccessRight right)
{
Add (right);
}
/// <summary>
/// Add the specified access right.
/// </summary>
/// <remarks>
/// Adds the specified access right if it is not already included.
/// </remarks>
/// <returns><c>true</c> if the right was added; otherwise, <c>false</c>.</returns>
/// <param name="right">The access right.</param>
public bool Add (AccessRight right)
{
if (list.Contains (right))
return false;
list.Add (right);
return true;
}
/// <summary>
/// Add the specified right.
/// </summary>
/// <remarks>
/// Adds the right specified by the given character.
/// </remarks>
/// <returns><c>true</c> if the right was added; otherwise, <c>false</c>.</returns>
/// <param name="right">The right.</param>
public bool Add (char right)
{
return Add (new AccessRight (right));
}
/// <summary>
/// Add the rights specified by the characters in the given string.
/// </summary>
/// <remarks>
/// Adds the rights specified by the characters in the given string.
/// </remarks>
/// <param name="rights">The rights.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="rights"/> is <c>null</c>.
/// </exception>
public void AddRange (string rights)
{
if (rights == null)
throw new ArgumentNullException (nameof (rights));
for (int i = 0; i < rights.Length; i++)
Add (new AccessRight (rights[i]));
}
/// <summary>
/// Add the range of specified rights.
/// </summary>
/// <remarks>
/// Adds the range of specified rights.
/// </remarks>
/// <param name="rights">The rights.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="rights"/> is <c>null</c>.
/// </exception>
public void AddRange (IEnumerable<AccessRight> rights)
{
if (rights == null)
throw new ArgumentNullException (nameof (rights));
foreach (var right in rights)
Add (right);
}
/// <summary>
/// Clears the access rights.
/// </summary>
/// <remarks>
/// Removes all of the access rights.
/// </remarks>
public void Clear ()
{
list.Clear ();
}
/// <summary>
/// Checks if the set of access rights contains the specified right.
/// </summary>
/// <remarks>
/// Determines whether or not the set of access rights already contains the specified right
/// </remarks>
/// <returns><value>true</value> if the specified right exists; otherwise <value>false</value>.</returns>
/// <param name="right">The access right.</param>
public bool Contains (AccessRight right)
{
return list.Contains (right);
}
/// <summary>
/// Copies all of the access rights to the specified array.
/// </summary>
/// <remarks>
/// Copies all of the access rights into the array,
/// starting at the specified array index.
/// </remarks>
/// <param name="array">The array.</param>
/// <param name="arrayIndex">The array index.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="array"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="arrayIndex"/> is out of range.
/// </exception>
public void CopyTo (AccessRight[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException (nameof (array));
if (arrayIndex < 0 || arrayIndex + Count > array.Length)
throw new ArgumentOutOfRangeException (nameof (arrayIndex));
list.CopyTo (array, arrayIndex);
}
/// <summary>
/// Removes the specified access right.
/// </summary>
/// <remarks>
/// Removes the specified access right.
/// </remarks>
/// <returns><value>true</value> if the access right was removed; otherwise <value>false</value>.</returns>
/// <param name="right">The access right.</param>
public bool Remove (AccessRight right)
{
return list.Remove (right);
}
/// <summary>
/// Get the access right at the specified index.
/// </summary>
/// <remarks>
/// Gets the access right at the specified index.
/// </remarks>
/// <value>The access right at the specified index.</value>
/// <param name="index">The index.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public AccessRight this [int index] {
get {
if (index < 0 || index >= list.Count)
throw new ArgumentOutOfRangeException (nameof (index));
return list[index];
}
}
#region IEnumerable implementation
/// <summary>
/// Get the access rights enumerator.
/// </summary>
/// <remarks>
/// Gets the access rights enumerator.
/// </remarks>
/// <returns>The enumerator.</returns>
public IEnumerator<AccessRight> GetEnumerator ()
{
return list.GetEnumerator ();
}
#endregion
#region IEnumerable implementation
/// <summary>
/// Get the access rights enumerator.
/// </summary>
/// <remarks>
/// Gets the access rights enumerator.
/// </remarks>
/// <returns>The enumerator.</returns>
IEnumerator IEnumerable.GetEnumerator ()
{
return list.GetEnumerator ();
}
#endregion
/// <summary>
/// Return a <see cref="System.String"/> that represents the current <see cref="MailKit.AccessRights"/>.
/// </summary>
/// <remarks>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AccessRights"/>.
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.AccessRights"/>.</returns>
public override string ToString ()
{
var rights = new char[list.Count];
for (int i = 0; i < list.Count; i++)
rights[i] = list[i].Right;
return new string (rights);
}
}
}

View File

@ -0,0 +1,69 @@
//
// AlertEventArgs.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;
namespace MailKit {
/// <summary>
/// Alert event arguments.
/// </summary>
/// <remarks>
/// Some <see cref="IMailStore"/> implementations, such as
/// <see cref="MailKit.Net.Imap.ImapClient"/>, will emit Alert
/// events when they receive alert messages from the server.
/// </remarks>
public class AlertEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AlertEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AlertEventArgs"/>.
/// </remarks>
/// <param name="message">The alert message.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="message"/> is <c>null</c>.
/// </exception>
public AlertEventArgs (string message)
{
if (message == null)
throw new ArgumentNullException (nameof (message));
Message = message;
}
/// <summary>
/// Gets the alert message.
/// </summary>
/// <remarks>
/// The alert message will be the exact message received from the server.
/// </remarks>
/// <value>The alert message.</value>
public string Message {
get; private set;
}
}
}

81
src/MailKit/Annotation.cs Normal file
View File

@ -0,0 +1,81 @@
//
// Annotation.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.Collections.Generic;
namespace MailKit {
/// <summary>
/// An annotation.
/// </summary>
/// <remarks>
/// <para>An annotation.</para>
/// <para>For more information about annotations, see
/// <a href="https://tools.ietf.org/html/rfc5257">rfc5257</a>.</para>
/// </remarks>
public class Annotation
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Annotation"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="Annotation"/>.
/// </remarks>
/// <param name="entry">The annotation entry.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="entry"/> is <c>null</c>.
/// </exception>
public Annotation (AnnotationEntry entry)
{
if (entry == null)
throw new ArgumentNullException (nameof (entry));
Properties = new Dictionary<AnnotationAttribute, string> ();
Entry = entry;
}
/// <summary>
/// Get the annotation tag.
/// </summary>
/// <remarks>
/// Gets the annotation tag.
/// </remarks>
/// <value>The annotation tag.</value>
public AnnotationEntry Entry {
get; private set;
}
/// <summary>
/// Get the annotation properties.
/// </summary>
/// <remarks>
/// Gets the annotation properties.
/// </remarks>
public Dictionary<AnnotationAttribute, string> Properties {
get; private set;
}
}
}

View File

@ -0,0 +1,53 @@
//
// AnnotationAccess.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.
//
namespace MailKit {
/// <summary>
/// An annotation access level.
/// </summary>
/// <remarks>
/// <para>An annotation access level.</para>
/// <para>For more information about annotations, see
/// <a href="https://tools.ietf.org/html/rfc5257">rfc5257</a>.</para>
/// </remarks>
public enum AnnotationAccess
{
/// <summary>
/// Annotations are not supported.
/// </summary>
None,
/// <summary>
/// Annotations are read-only.
/// </summary>
ReadOnly,
/// <summary>
/// Annotations are read-write.
/// </summary>
ReadWrite
}
}

View File

@ -0,0 +1,251 @@
//
// AnnotationAttribute.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;
namespace MailKit {
/// <summary>
/// An annotation attribute.
/// </summary>
/// <remarks>
/// <para>An annotation attribute.</para>
/// <para>For more information about annotations, see
/// <a href="https://tools.ietf.org/html/rfc5257">rfc5257</a>.</para>
/// </remarks>
public class AnnotationAttribute : IEquatable<AnnotationAttribute>
{
static readonly char[] Wildcards = { '*', '%' };
/// <summary>
/// The annotation value.
/// </summary>
/// <remarks>
/// Used to get or set both the private and shared values of an annotation.
/// </remarks>
public static readonly AnnotationAttribute Value = new AnnotationAttribute ("value", AnnotationScope.Both);
/// <summary>
/// The shared annotation value.
/// </summary>
/// <remarks>
/// Used to get or set the shared value of an annotation.
/// </remarks>
public static readonly AnnotationAttribute SharedValue = new AnnotationAttribute ("value", AnnotationScope.Shared);
/// <summary>
/// The private annotation value.
/// </summary>
/// <remarks>
/// Used to get or set the private value of an annotation.
/// </remarks>
public static readonly AnnotationAttribute PrivateValue = new AnnotationAttribute ("value", AnnotationScope.Private);
/// <summary>
/// The size of an annotation value.
/// </summary>
/// <remarks>
/// Used to get the size of the both the private and shared annotation values.
/// </remarks>
public static readonly AnnotationAttribute Size = new AnnotationAttribute ("size", AnnotationScope.Both);
/// <summary>
/// The size of a shared annotation value.
/// </summary>
/// <remarks>
/// Used to get the size of a shared annotation value.
/// </remarks>
public static readonly AnnotationAttribute SharedSize = new AnnotationAttribute ("size", AnnotationScope.Shared);
/// <summary>
/// The size of a private annotation value.
/// </summary>
/// <remarks>
/// Used to get the size of a private annotation value.
/// </remarks>
public static readonly AnnotationAttribute PrivateSize = new AnnotationAttribute ("size", AnnotationScope.Private);
AnnotationAttribute (string name, AnnotationScope scope)
{
switch (scope) {
case AnnotationScope.Shared: Specifier = string.Format ("{0}.shared", name); break;
case AnnotationScope.Private: Specifier = string.Format ("{0}.priv", name); break;
default: Specifier = name; break;
}
Scope = scope;
Name = name;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AnnotationAttribute"/> class.
/// </summary>
/// <param name="specifier">The annotation attribute specifier.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="specifier"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="specifier"/> contains illegal characters.
/// </exception>
public AnnotationAttribute (string specifier)
{
if (specifier == null)
throw new ArgumentNullException (nameof (specifier));
if (specifier.Length == 0)
throw new ArgumentException ("Annotation attribute specifiers cannot be empty.", nameof (specifier));
// TODO: improve validation
if (specifier.IndexOfAny (Wildcards) != -1)
throw new ArgumentException ("Annotation attribute specifiers cannot contain '*' or '%'.", nameof (specifier));
Specifier = specifier;
if (specifier.EndsWith (".shared", StringComparison.Ordinal)) {
Name = specifier.Substring (0, specifier.Length - ".shared".Length);
Scope = AnnotationScope.Shared;
} else if (specifier.EndsWith (".priv", StringComparison.Ordinal)) {
Name = specifier.Substring (0, specifier.Length - ".priv".Length);
Scope = AnnotationScope.Private;
} else {
Scope = AnnotationScope.Both;
Name = specifier;
}
}
/// <summary>
/// Get the name of the annotation attribute.
/// </summary>
/// <remarks>
/// Gets the name of the annotation attribute.
/// </remarks>
public string Name {
get; private set;
}
/// <summary>
/// Get the scope of the annotation attribute.
/// </summary>
/// <remarks>
/// Gets the scope of the annotation attribute.
/// </remarks>
public AnnotationScope Scope {
get; private set;
}
/// <summary>
/// Get the annotation attribute specifier.
/// </summary>
/// <remarks>
/// Gets the annotation attribute specifier.
/// </remarks>
public string Specifier {
get; private set;
}
#region IEquatable implementation
/// <summary>
/// Determines whether the specified <see cref="MailKit.AnnotationAttribute"/> is equal to the current <see cref="MailKit.AnnotationAttribute"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="MailKit.AnnotationAttribute"/> is equal to the current <see cref="MailKit.AnnotationAttribute"/>.
/// </remarks>
/// <param name="other">The <see cref="MailKit.AnnotationAttribute"/> to compare with the current <see cref="MailKit.AnnotationAttribute"/>.</param>
/// <returns><c>true</c> if the specified <see cref="MailKit.AnnotationAttribute"/> is equal to the current
/// <see cref="MailKit.AnnotationAttribute"/>; otherwise, <c>false</c>.</returns>
public bool Equals (AnnotationAttribute other)
{
return other?.Specifier == Specifier;
}
#endregion
/// <summary>
/// Determines whether two annotation attributes are equal.
/// </summary>
/// <remarks>
/// Determines whether two annotation attributes are equal.
/// </remarks>
/// <returns><c>true</c> if <paramref name="attr1"/> and <paramref name="attr2"/> are equal; otherwise, <c>false</c>.</returns>
/// <param name="attr1">The first annotation attribute to compare.</param>
/// <param name="attr2">The second annotation attribute to compare.</param>
public static bool operator == (AnnotationAttribute attr1, AnnotationAttribute attr2)
{
return attr1?.Specifier == attr2?.Specifier;
}
/// <summary>
/// Determines whether two annotation attributes are not equal.
/// </summary>
/// <remarks>
/// Determines whether two annotation attributes are not equal.
/// </remarks>
/// <returns><c>true</c> if <paramref name="attr1"/> and <paramref name="attr2"/> are not equal; otherwise, <c>false</c>.</returns>
/// <param name="attr1">The first annotation attribute to compare.</param>
/// <param name="attr2">The second annotation attribute to compare.</param>
public static bool operator != (AnnotationAttribute attr1, AnnotationAttribute attr2)
{
return attr1?.Specifier != attr2?.Specifier;
}
/// <summary>
/// Determine whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AnnotationAttribute"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AnnotationAttribute"/>.
/// </remarks>
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="MailKit.AnnotationAttribute"/>.</param>
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
/// <see cref="MailKit.AnnotationAttribute"/>; otherwise, <c>false</c>.</returns>
public override bool Equals (object obj)
{
return obj is AnnotationAttribute && ((AnnotationAttribute) obj).Specifier == Specifier;
}
/// <summary>
/// Serves as a hash function for a <see cref="MailKit.AnnotationAttribute"/> object.
/// </summary>
/// <remarks>
/// Serves as a hash function for a <see cref="MailKit.AnnotationAttribute"/> object.
/// </remarks>
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table.</returns>
public override int GetHashCode ()
{
return Specifier.GetHashCode ();
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AnnotationAttribute"/>.
/// </summary>
/// <remarks>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AnnotationAttribute"/>.
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.AnnotationAttribute"/>.</returns>
public override string ToString ()
{
return Specifier;
}
}
}

View File

@ -0,0 +1,521 @@
//
// Annotationentry.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;
namespace MailKit {
/// <summary>
/// An annotation entry.
/// </summary>
/// <remarks>
/// <para>An annotation entry.</para>
/// <para>For more information about annotations, see
/// <a href="https://tools.ietf.org/html/rfc5257">rfc5257</a>.</para>
/// </remarks>
public class AnnotationEntry : IEquatable<AnnotationEntry>
{
/// <summary>
/// An annotation entry for a comment on a message.
/// </summary>
/// <remarks>
/// Used to get or set a comment on a message.
/// </remarks>
public static readonly AnnotationEntry Comment = new AnnotationEntry ("/comment", AnnotationScope.Both);
/// <summary>
/// An annotation entry for a private comment on a message.
/// </summary>
/// <remarks>
/// Used to get or set a private comment on a message.
/// </remarks>
public static readonly AnnotationEntry PrivateComment = new AnnotationEntry ("/comment", AnnotationScope.Private);
/// <summary>
/// An annotation entry for a shared comment on a message.
/// </summary>
/// <remarks>
/// Used to get or set a shared comment on a message.
/// </remarks>
public static readonly AnnotationEntry SharedComment = new AnnotationEntry ("/comment", AnnotationScope.Shared);
/// <summary>
/// An annotation entry for flags on a message.
/// </summary>
/// <remarks>
/// Used to get or set flags on a message.
/// </remarks>
public static readonly AnnotationEntry Flags = new AnnotationEntry ("/flags", AnnotationScope.Both);
/// <summary>
/// An annotation entry for private flags on a message.
/// </summary>
/// <remarks>
/// Used to get or set private flags on a message.
/// </remarks>
public static readonly AnnotationEntry PrivateFlags = new AnnotationEntry ("/flags", AnnotationScope.Private);
/// <summary>
/// Aa annotation entry for shared flags on a message.
/// </summary>
/// <remarks>
/// Used to get or set shared flags on a message.
/// </remarks>
public static readonly AnnotationEntry SharedFlags = new AnnotationEntry ("/flags", AnnotationScope.Shared);
/// <summary>
/// An annotation entry for an alternate subject on a message.
/// </summary>
/// <remarks>
/// Used to get or set an alternate subject on a message.
/// </remarks>
public static readonly AnnotationEntry AltSubject = new AnnotationEntry ("/altsubject", AnnotationScope.Both);
/// <summary>
/// An annotation entry for a private alternate subject on a message.
/// </summary>
/// <remarks>
/// Used to get or set a private alternate subject on a message.
/// </remarks>
public static readonly AnnotationEntry PrivateAltSubject = new AnnotationEntry ("/altsubject", AnnotationScope.Private);
/// <summary>
/// An annotation entry for a shared alternate subject on a message.
/// </summary>
/// <remarks>
/// Used to get or set a shared alternate subject on a message.
/// </remarks>
public static readonly AnnotationEntry SharedAltSubject = new AnnotationEntry ("/altsubject", AnnotationScope.Shared);
static void ValidatePath (string path)
{
if (path == null)
throw new ArgumentNullException (nameof (path));
if (path.Length == 0)
throw new ArgumentException ("Annotation entry paths cannot be empty.", nameof (path));
if (path[0] != '/' && path[0] != '*' && path[0] != '%')
throw new ArgumentException ("Annotation entry paths must begin with '/'.", nameof (path));
if (path.Length > 1 && path[1] >= '0' && path[1] <= '9')
throw new ArgumentException ("Annotation entry paths must not include a part-specifier.", nameof (path));
if (path == "*" || path == "%")
return;
char pc = path[0];
for (int i = 1; i < path.Length; i++) {
char c = path[i];
if (c > 127)
throw new ArgumentException ($"Invalid character in annotation entry path: '{c}'.", nameof (path));
if (c >= '0' && c <= '9' && pc == '/')
throw new ArgumentException ("Invalid annotation entry path.", nameof (path));
if ((pc == '/' || pc == '.') && (c == '/' || c == '.'))
throw new ArgumentException ("Invalid annotation entry path.", nameof (path));
pc = c;
}
int endIndex = path.Length - 1;
if (path[endIndex] == '/')
throw new ArgumentException ("Annotation entry paths must not end with '/'.", nameof (path));
if (path[endIndex] == '.')
throw new ArgumentException ("Annotation entry paths must not end with '.'.", nameof (path));
}
static void ValidatePartSpecifier (string partSpecifier)
{
if (partSpecifier == null)
throw new ArgumentNullException (nameof (partSpecifier));
char pc = '\0';
for (int i = 0; i < partSpecifier.Length; i++) {
char c = partSpecifier[i];
if (!((c >= '0' && c <= '9') || c == '.') || (c == '.' && (pc == '.' || pc == '\0')))
throw new ArgumentException ("Invalid part-specifier.", nameof (partSpecifier));
pc = c;
}
if (pc == '.')
throw new ArgumentException ("Invalid part-specifier.", nameof (partSpecifier));
}
AnnotationEntry ()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AnnotationEntry"/> struct.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AnnotationEntry"/>.
/// </remarks>
/// <param name="path">The annotation entry path.</param>
/// <param name="scope">The scope of the annotation.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="path"/> is invalid.
/// </exception>
public AnnotationEntry (string path, AnnotationScope scope = AnnotationScope.Both)
{
ValidatePath (path);
switch (scope) {
case AnnotationScope.Private: Entry = path + ".priv"; break;
case AnnotationScope.Shared: Entry = path + ".shared"; break;
default: Entry = path; break;
}
PartSpecifier = null;
Path = path;
Scope = scope;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AnnotationEntry"/> struct.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AnnotationEntry"/> for an individual body part of a message.
/// </remarks>
/// <param name="partSpecifier">The part-specifier of the body part of the message.</param>
/// <param name="path">The annotation entry path.</param>
/// <param name="scope">The scope of the annotation.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="partSpecifier"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="path"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para><paramref name="partSpecifier"/> is invalid.</para>
/// <para>-or-</para>
/// <para><paramref name="path"/> is invalid.</para>
/// </exception>
public AnnotationEntry (string partSpecifier, string path, AnnotationScope scope = AnnotationScope.Both)
{
ValidatePartSpecifier (partSpecifier);
ValidatePath (path);
switch (scope) {
case AnnotationScope.Private: Entry = string.Format ("/{0}{1}.priv", partSpecifier, path); break;
case AnnotationScope.Shared: Entry = string.Format ("/{0}{1}.shared", partSpecifier, path); break;
default: Entry = string.Format ("/{0}{1}", partSpecifier, path); break;
}
PartSpecifier = partSpecifier;
Path = path;
Scope = scope;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AnnotationEntry"/> struct.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AnnotationEntry"/> for an individual body part of a message.
/// </remarks>
/// <param name="part">The body part of the message.</param>
/// <param name="path">The annotation entry path.</param>
/// <param name="scope">The scope of the annotation.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="part"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="path"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="path"/> is invalid.
/// </exception>
public AnnotationEntry (BodyPart part, string path, AnnotationScope scope = AnnotationScope.Both)
{
if (part == null)
throw new ArgumentNullException (nameof (part));
ValidatePath (path);
switch (scope) {
case AnnotationScope.Private: Entry = string.Format ("/{0}{1}.priv", part.PartSpecifier, path); break;
case AnnotationScope.Shared: Entry = string.Format ("/{0}{1}.shared", part.PartSpecifier, path); break;
default: Entry = string.Format ("/{0}{1}", part.PartSpecifier, path); break;
}
PartSpecifier = part.PartSpecifier;
Path = path;
Scope = scope;
}
/// <summary>
/// Get the annotation entry specifier.
/// </summary>
/// <remarks>
/// Gets the annotation entry specifier.
/// </remarks>
/// <value>The annotation entry specifier.</value>
public string Entry {
get; private set;
}
/// <summary>
/// Get the part-specifier component of the annotation entry.
/// </summary>
/// <remarks>
/// Gets the part-specifier component of the annotation entry.
/// </remarks>
public string PartSpecifier {
get; private set;
}
/// <summary>
/// Get the path component of the annotation entry.
/// </summary>
/// <remarks>
/// Gets the path component of the annotation entry.
/// </remarks>
public string Path {
get; private set;
}
/// <summary>
/// Get the scope of the annotation.
/// </summary>
/// <remarks>
/// Gets the scope of the annotation.
/// </remarks>
public AnnotationScope Scope {
get; private set;
}
#region IEquatable implementation
/// <summary>
/// Determines whether the specified <see cref="MailKit.AnnotationEntry"/> is equal to the current <see cref="MailKit.AnnotationEntry"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="MailKit.AnnotationEntry"/> is equal to the current <see cref="MailKit.AnnotationEntry"/>.
/// </remarks>
/// <param name="other">The <see cref="MailKit.AnnotationEntry"/> to compare with the current <see cref="MailKit.AnnotationEntry"/>.</param>
/// <returns><c>true</c> if the specified <see cref="MailKit.AnnotationEntry"/> is equal to the current
/// <see cref="MailKit.AnnotationEntry"/>; otherwise, <c>false</c>.</returns>
public bool Equals (AnnotationEntry other)
{
return other?.Entry == Entry;
}
#endregion
/// <summary>
/// Determines whether two annotation entries are equal.
/// </summary>
/// <remarks>
/// Determines whether two annotation entries are equal.
/// </remarks>
/// <returns><c>true</c> if <paramref name="entry1"/> and <paramref name="entry2"/> are equal; otherwise, <c>false</c>.</returns>
/// <param name="entry1">The first annotation entry to compare.</param>
/// <param name="entry2">The second annotation entry to compare.</param>
public static bool operator == (AnnotationEntry entry1, AnnotationEntry entry2)
{
return entry1?.Entry == entry2?.Entry;
}
/// <summary>
/// Determines whether two annotation entries are not equal.
/// </summary>
/// <remarks>
/// Determines whether two annotation entries are not equal.
/// </remarks>
/// <returns><c>true</c> if <paramref name="entry1"/> and <paramref name="entry2"/> are not equal; otherwise, <c>false</c>.</returns>
/// <param name="entry1">The first annotation entry to compare.</param>
/// <param name="entry2">The second annotation entry to compare.</param>
public static bool operator != (AnnotationEntry entry1, AnnotationEntry entry2)
{
return entry1?.Entry != entry2?.Entry;
}
/// <summary>
/// Determine whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AnnotationEntry"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.AnnotationEntry"/>.
/// </remarks>
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="MailKit.AnnotationEntry"/>.</param>
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
/// <see cref="MailKit.AnnotationEntry"/>; otherwise, <c>false</c>.</returns>
public override bool Equals (object obj)
{
return obj is AnnotationEntry && ((AnnotationEntry) obj).Entry == Entry;
}
/// <summary>
/// Serves as a hash function for a <see cref="MailKit.AnnotationEntry"/> object.
/// </summary>
/// <remarks>
/// Serves as a hash function for a <see cref="MailKit.AnnotationEntry"/> object.
/// </remarks>
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table.</returns>
public override int GetHashCode ()
{
return Entry.GetHashCode ();
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AnnotationEntry"/>.
/// </summary>
/// <remarks>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.AnnotationEntry"/>.
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.AnnotationEntry"/>.</returns>
public override string ToString ()
{
return Entry;
}
/// <summary>
/// Parse an annotation entry.
/// </summary>
/// <remarks>
/// Parses an annotation entry.
/// </remarks>
/// <param name="entry">The annotation entry.</param>
/// <returns>The parsed annotation entry.</returns>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="entry"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.FormatException">
/// <paramref name="entry"/> does not conform to the annotation entry syntax.
/// </exception>
public static AnnotationEntry Parse (string entry)
{
if (entry == null)
throw new ArgumentNullException (nameof (entry));
if (entry.Length == 0)
throw new FormatException ("An annotation entry cannot be empty.");
if (entry[0] != '/' && entry[0] != '*' && entry[0] != '%')
throw new FormatException ("An annotation entry must begin with a '/' character.");
var scope = AnnotationScope.Both;
int startIndex = 0, endIndex;
string partSpecifier = null;
var component = 0;
var pc = entry[0];
string path;
for (int i = 1; i < entry.Length; i++) {
char c = entry[i];
if (c >= '0' && c <= '9' && pc == '/') {
if (component > 0)
throw new FormatException ("Invalid annotation entry.");
startIndex = i;
endIndex = i + 1;
pc = c;
while (endIndex < entry.Length) {
c = entry[endIndex];
if (c == '/') {
if (pc == '.')
throw new FormatException ("Invalid part-specifier in annotation entry.");
break;
}
if (!(c >= '0' && c <= '9') && c != '.')
throw new FormatException ($"Invalid character in part-specifier: '{c}'.");
if (c == '.' && pc == '.')
throw new FormatException ("Invalid part-specifier in annotation entry.");
endIndex++;
pc = c;
}
if (endIndex >= entry.Length)
throw new FormatException ("Incomplete part-specifier in annotation entry.");
partSpecifier = entry.Substring (startIndex, endIndex - startIndex);
i = startIndex = endIndex;
component++;
} else if (c == '/' || c == '.') {
if (pc == '/' || pc == '.')
throw new FormatException ("Invalid annotation entry path.");
if (c == '/')
component++;
} else if (c > 127) {
throw new FormatException ($"Invalid character in annotation entry path: '{c}'.");
}
pc = c;
}
if (pc == '/' || pc == '.')
throw new FormatException ("Invalid annotation entry path.");
if (entry.EndsWith (".shared", StringComparison.Ordinal)) {
endIndex = entry.Length - ".shared".Length;
scope = AnnotationScope.Shared;
} else if (entry.EndsWith (".priv", StringComparison.Ordinal)) {
endIndex = entry.Length - ".priv".Length;
scope = AnnotationScope.Private;
} else {
endIndex = entry.Length;
}
path = entry.Substring (startIndex, endIndex - startIndex);
return new AnnotationEntry {
PartSpecifier = partSpecifier,
Entry = entry,
Path = path,
Scope = scope
};
}
internal static AnnotationEntry Create (string entry)
{
switch (entry) {
case "/comment": return Comment;
case "/comment.priv": return PrivateComment;
case "/comment.shared": return SharedComment;
case "/flags": return Flags;
case "/flags.priv": return PrivateFlags;
case "/flags.shared": return SharedFlags;
case "/altsubject": return AltSubject;
case "/altsubject.priv": return PrivateAltSubject;
case "/altsubject.shared": return SharedAltSubject;
default: return Parse (entry);
}
}
}
}

View File

@ -0,0 +1,61 @@
//
// AnnotationScope.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;
namespace MailKit {
/// <summary>
/// The scope of an annotation.
/// </summary>
/// <remarks>
/// <para>Represents the scope of an annotation.</para>
/// <para>For more information about annotations, see
/// <a href="https://tools.ietf.org/html/rfc5257">rfc5257</a>.</para>
/// </remarks>
[Flags]
public enum AnnotationScope
{
/// <summary>
/// No scopes.
/// </summary>
None,
/// <summary>
/// The private annotation scope.
/// </summary>
Private,
/// <summary>
/// The shared annotation scope.
/// </summary>
Shared,
/// <summary>
/// Both private and shared scopes.
/// </summary>
Both = Private | Shared
}
}

View File

@ -0,0 +1,93 @@
//
// AnnotationsChangedEventArgs.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.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace MailKit {
/// <summary>
/// Event args used when an annotation changes.
/// </summary>
/// <remarks>
/// Event args used when an annotation changes.
/// </remarks>
public class AnnotationsChangedEventArgs : MessageEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AnnotationsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AnnotationsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
internal AnnotationsChangedEventArgs (int index) : base (index)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.AnnotationsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AnnotationsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="annotations">The annotations that changed.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="annotations"/> is <c>null</c>.
/// </exception>
public AnnotationsChangedEventArgs (int index, IEnumerable<Annotation> annotations) : base (index)
{
if (annotations == null)
throw new ArgumentNullException (nameof (annotations));
Annotations = new ReadOnlyCollection<Annotation> (annotations.ToArray ());
}
/// <summary>
/// Get the annotations that changed.
/// </summary>
/// <remarks>
/// Gets the annotations that changed.
/// </remarks>
/// <value>The annotation.</value>
public IList<Annotation> Annotations {
get; internal set;
}
/// <summary>
/// Gets the updated mod-sequence value of the message, if available.
/// </summary>
/// <remarks>
/// Gets the updated mod-sequence value of the message, if available.
/// </remarks>
/// <value>The mod-sequence value.</value>
public ulong? ModSeq {
get; internal set;
}
}
}

View File

@ -0,0 +1,68 @@
//
// AuthenticatedEventArgs.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;
namespace MailKit {
/// <summary>
/// Authenticated event arguments.
/// </summary>
/// <remarks>
/// Some servers, such as GMail IMAP, will send some free-form text in
/// the response to a successful login.
/// </remarks>
public class AuthenticatedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.AuthenticatedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="AuthenticatedEventArgs"/>.
/// </remarks>
/// <param name="message">The free-form text.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="message"/> is <c>null</c>.
/// </exception>
public AuthenticatedEventArgs (string message)
{
if (message == null)
throw new ArgumentNullException (nameof (message));
Message = message;
}
/// <summary>
/// Get the free-form text sent by the server.
/// </summary>
/// <remarks>
/// Gets the free-form text sent by the server.
/// </remarks>
/// <value>The free-form text sent by the server.</value>
public string Message {
get; private set;
}
}
}

716
src/MailKit/BodyPart.cs Normal file
View File

@ -0,0 +1,716 @@
//
// BodyPart.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.Text;
using System.Collections.Generic;
using MimeKit;
using MimeKit.Utils;
namespace MailKit {
/// <summary>
/// An abstract body part of a message.
/// </summary>
/// <remarks>
/// Each body part will actually be a <see cref="BodyPartBasic"/>,
/// <see cref="BodyPartText"/>, <see cref="BodyPartMessage"/>, or
/// <see cref="BodyPartMultipart"/>.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
public abstract class BodyPart
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.BodyPart"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.BodyPart"/>.
/// </remarks>
protected BodyPart ()
{
}
/// <summary>
/// Gets the Content-Type of the body part.
/// </summary>
/// <remarks>
/// Gets the Content-Type of the body part.
/// </remarks>
/// <value>The content type.</value>
public ContentType ContentType {
get; set;
}
/// <summary>
/// Gets the part specifier.
/// </summary>
/// <remarks>
/// Gets the part specifier.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
/// <value>The part specifier.</value>
public string PartSpecifier {
get; set;
}
/// <summary>
/// Dispatches to the specific visit method for this MIME body part.
/// </summary>
/// <remarks>
/// This default implementation for <see cref="MailKit.BodyPart"/> nodes
/// calls <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>. Override this
/// method to call into a more specific method on a derived visitor class
/// of the <see cref="MailKit.BodyPartVisitor"/> class. However, it should still
/// support unknown visitors by calling
/// <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>.
/// </remarks>
/// <param name="visitor">The visitor.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="visitor"/> is <c>null</c>.
/// </exception>
public abstract void Accept (BodyPartVisitor visitor);
internal static void Encode (StringBuilder builder, uint value)
{
builder.Append (value.ToString ());
}
internal static void Encode (StringBuilder builder, string value)
{
if (value != null)
builder.Append (MimeUtils.Quote (value));
else
builder.Append ("NIL");
}
internal static void Encode (StringBuilder builder, Uri location)
{
if (location != null)
builder.Append (MimeUtils.Quote (location.ToString ()));
else
builder.Append ("NIL");
}
internal static void Encode (StringBuilder builder, string[] values)
{
if (values == null || values.Length == 0) {
builder.Append ("NIL");
return;
}
builder.Append ('(');
for (int i = 0; i < values.Length; i++) {
if (i > 0)
builder.Append (' ');
Encode (builder, values[i]);
}
builder.Append (')');
}
internal static void Encode (StringBuilder builder, IList<Parameter> parameters)
{
if (parameters == null || parameters.Count == 0) {
builder.Append ("NIL");
return;
}
builder.Append ('(');
for (int i = 0; i < parameters.Count; i++) {
if (i > 0)
builder.Append (' ');
Encode (builder, parameters[i].Name);
builder.Append (' ');
Encode (builder, parameters[i].Value);
}
builder.Append (')');
}
internal static void Encode (StringBuilder builder, ContentDisposition disposition)
{
if (disposition == null) {
builder.Append ("NIL");
return;
}
builder.Append ('(');
Encode (builder, disposition.Disposition);
builder.Append (' ');
Encode (builder, disposition.Parameters);
builder.Append (')');
}
internal static void Encode (StringBuilder builder, ContentType contentType)
{
Encode (builder, contentType.MediaType);
builder.Append (' ');
Encode (builder, contentType.MediaSubtype);
builder.Append (' ');
Encode (builder, contentType.Parameters);
}
internal static void Encode (StringBuilder builder, BodyPartCollection parts)
{
if (parts == null || parts.Count == 0) {
builder.Append ("NIL");
return;
}
for (int i = 0; i < parts.Count; i++) {
if (i > 0)
builder.Append (' ');
Encode (builder, parts[i]);
}
}
internal static void Encode (StringBuilder builder, Envelope envelope)
{
if (envelope == null) {
builder.Append ("NIL");
return;
}
envelope.Encode (builder);
}
internal static void Encode (StringBuilder builder, BodyPart body)
{
if (body == null) {
builder.Append ("NIL");
return;
}
builder.Append ('(');
body.Encode (builder);
builder.Append (')');
}
/// <summary>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </summary>
/// <remarks>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </remarks>
/// <param name="builder">The string builder.</param>
protected abstract void Encode (StringBuilder builder);
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.BodyPart"/>.
/// </summary>
/// <remarks>
/// <para>Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.BodyPart"/>.</para>
/// <note type="note">The syntax of the string returned, while similar to IMAP's BODYSTRUCTURE syntax,
/// is not completely compatible.</note>
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.BodyPart"/>.</returns>
public override string ToString ()
{
var builder = new StringBuilder ();
builder.Append ('(');
Encode (builder);
builder.Append (')');
return builder.ToString ();
}
static bool TryParse (string text, ref int index, out uint value)
{
while (index < text.Length && text[index] == ' ')
index++;
int startIndex = index;
value = 0;
while (index < text.Length && char.IsDigit (text[index]))
value = (value * 10) + (uint) (text[index++] - '0');
return index > startIndex;
}
static bool TryParse (string text, ref int index, out string nstring)
{
nstring = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (text[index] != '"') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
index += 3;
return true;
}
return false;
}
var token = new StringBuilder ();
bool escaped = false;
index++;
while (index < text.Length) {
if (text[index] == '"' && !escaped)
break;
if (escaped || text[index] != '\\') {
token.Append (text[index]);
escaped = false;
} else {
escaped = true;
}
index++;
}
if (index >= text.Length)
return false;
nstring = token.ToString ();
index++;
return true;
}
static bool TryParse (string text, ref int index, out string[] values)
{
values = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (text[index] != '(') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
index += 3;
return true;
}
return false;
}
index++;
if (index >= text.Length)
return false;
var list = new List<string> ();
string value;
do {
if (text[index] == ')')
break;
if (!TryParse (text, ref index, out value))
return false;
list.Add (value);
} while (index < text.Length);
if (index >= text.Length || text[index] != ')')
return false;
values = list.ToArray ();
index++;
return true;
}
static bool TryParse (string text, ref int index, out Uri uri)
{
string nstring;
uri = null;
if (!TryParse (text, ref index, out nstring))
return false;
if (!string.IsNullOrEmpty (nstring)) {
if (Uri.IsWellFormedUriString (nstring, UriKind.Absolute))
uri = new Uri (nstring, UriKind.Absolute);
else if (Uri.IsWellFormedUriString (nstring, UriKind.Relative))
uri = new Uri (nstring, UriKind.Relative);
}
return true;
}
static bool TryParse (string text, ref int index, out IList<Parameter> parameters)
{
string name, value;
parameters = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (text[index] != '(') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
parameters = new List<Parameter> ();
index += 3;
return true;
}
return false;
}
index++;
if (index >= text.Length)
return false;
parameters = new List<Parameter> ();
do {
if (text[index] == ')')
break;
if (!TryParse (text, ref index, out name))
return false;
if (!TryParse (text, ref index, out value))
return false;
parameters.Add (new Parameter (name, value));
} while (index < text.Length);
if (index >= text.Length || text[index] != ')')
return false;
index++;
return true;
}
static bool TryParse (string text, ref int index, out ContentDisposition disposition)
{
IList<Parameter> parameters;
string value;
disposition = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (text[index] != '(') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
index += 3;
return true;
}
return false;
}
index++;
if (!TryParse (text, ref index, out value))
return false;
if (!TryParse (text, ref index, out parameters))
return false;
if (index >= text.Length || text[index] != ')')
return false;
index++;
disposition = new ContentDisposition (value);
foreach (var param in parameters)
disposition.Parameters.Add (param);
return true;
}
static bool TryParse (string text, ref int index, bool multipart, out ContentType contentType)
{
IList<Parameter> parameters;
string type, subtype;
contentType = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (!multipart) {
if (!TryParse (text, ref index, out type))
return false;
} else {
type = "multipart";
}
if (!TryParse (text, ref index, out subtype))
return false;
if (!TryParse (text, ref index, out parameters))
return false;
contentType = new ContentType (type ?? "application", subtype ?? "octet-stream");
foreach (var param in parameters)
contentType.Parameters.Add (param);
return true;
}
static bool TryParse (string text, ref int index, string prefix, out IList<BodyPart> children)
{
BodyPart part;
string path;
int id = 1;
children = null;
if (index >= text.Length)
return false;
children = new List<BodyPart> ();
do {
if (text[index] != '(')
break;
path = prefix + id;
if (!TryParse (text, ref index, path, out part))
return false;
while (index < text.Length && text[index] == ' ')
index++;
children.Add (part);
id++;
} while (index < text.Length);
return index < text.Length;
}
static bool TryParse (string text, ref int index, string path, out BodyPart part)
{
ContentDisposition disposition;
ContentType contentType;
string[] array;
string nstring;
Uri location;
uint number;
part = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length || text[index] != '(') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
index += 3;
return true;
}
return false;
}
index++;
if (index >= text.Length)
return false;
if (text[index] == '(') {
var prefix = path.Length > 0 ? path + "." : string.Empty;
var multipart = new BodyPartMultipart ();
IList<BodyPart> children;
if (!TryParse (text, ref index, prefix, out children))
return false;
foreach (var child in children)
multipart.BodyParts.Add (child);
if (!TryParse (text, ref index, true, out contentType))
return false;
multipart.ContentType = contentType;
if (!TryParse (text, ref index, out disposition))
return false;
multipart.ContentDisposition = disposition;
if (!TryParse (text, ref index, out array))
return false;
multipart.ContentLanguage = array;
if (!TryParse (text, ref index, out location))
return false;
multipart.ContentLocation = location;
part = multipart;
} else {
BodyPartMessage message = null;
BodyPartText txt = null;
BodyPartBasic basic;
if (!TryParse (text, ref index, false, out contentType))
return false;
if (contentType.IsMimeType ("message", "rfc822"))
basic = message = new BodyPartMessage ();
else if (contentType.IsMimeType ("text", "*"))
basic = txt = new BodyPartText ();
else
basic = new BodyPartBasic ();
basic.ContentType = contentType;
if (!TryParse (text, ref index, out nstring))
return false;
basic.ContentId = nstring;
if (!TryParse (text, ref index, out nstring))
return false;
basic.ContentDescription = nstring;
if (!TryParse (text, ref index, out nstring))
return false;
basic.ContentTransferEncoding = nstring;
if (!TryParse (text, ref index, out number))
return false;
basic.Octets = number;
if (!TryParse (text, ref index, out nstring))
return false;
basic.ContentMd5 = nstring;
if (!TryParse (text, ref index, out disposition))
return false;
basic.ContentDisposition = disposition;
if (!TryParse (text, ref index, out array))
return false;
basic.ContentLanguage = array;
if (!TryParse (text, ref index, out location))
return false;
basic.ContentLocation = location;
if (message != null) {
Envelope envelope;
BodyPart body;
if (!Envelope.TryParse (text, ref index, out envelope))
return false;
message.Envelope = envelope;
if (!TryParse (text, ref index, path, out body))
return false;
message.Body = body;
if (!TryParse (text, ref index, out number))
return false;
message.Lines = number;
} else if (txt != null) {
if (!TryParse (text, ref index, out number))
return false;
txt.Lines = number;
}
part = basic;
}
part.PartSpecifier = path;
if (index >= text.Length || text[index] != ')')
return false;
index++;
return true;
}
/// <summary>
/// Tries to parse the given text into a new <see cref="MailKit.BodyPart"/> instance.
/// </summary>
/// <remarks>
/// <para>Parses a body part from the specified text.</para>
/// <note type="note">This syntax, while similar to IMAP's BODYSTRUCTURE syntax, is not completely
/// compatible.</note>
/// </remarks>
/// <returns><c>true</c>, if the body part was successfully parsed, <c>false</c> otherwise.</returns>
/// <param name="text">The text to parse.</param>
/// <param name="part">The parsed body part.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="text"/> is <c>null</c>.
/// </exception>
public static bool TryParse (string text, out BodyPart part)
{
if (text == null)
throw new ArgumentNullException (nameof (text));
int index = 0;
return TryParse (text, ref index, string.Empty, out part) && index == text.Length;
}
}
}

View File

@ -0,0 +1,245 @@
//
// BodyPartBasic.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.Text;
using MimeKit;
namespace MailKit {
/// <summary>
/// A basic message body part.
/// </summary>
/// <remarks>
/// Represents any message body part that is not a multipart,
/// message/rfc822 part, or a text part.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
public class BodyPartBasic : BodyPart
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.BodyPartBasic"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="BodyPartBasic"/>.
/// </remarks>
public BodyPartBasic ()
{
}
/// <summary>
/// Gets the Content-Id of the body part, if available.
/// </summary>
/// <remarks>
/// Gets the Content-Id of the body part, if available.
/// </remarks>
/// <value>The content identifier.</value>
public string ContentId {
get; set;
}
/// <summary>
/// Gets the Content-Description of the body part, if available.
/// </summary>
/// <remarks>
/// Gets the Content-Description of the body part, if available.
/// </remarks>
/// <value>The content description.</value>
public string ContentDescription {
get; set;
}
/// <summary>
/// Gets the Content-Transfer-Encoding of the body part.
/// </summary>
/// <remarks>
/// <para>Gets the Content-Transfer-Encoding of the body part.</para>
/// <para>Hint: Use the <a href="M_MimeKit_Utils_MimeUtils_TryParse_1.htm">MimeUtils.TryParse</a>
/// method to parse this value into a usable <see cref="MimeKit.ContentEncoding"/>.</para>
/// </remarks>
/// <value>The content transfer encoding.</value>
public string ContentTransferEncoding {
get; set;
}
/// <summary>
/// Gets the size of the body part, in bytes.
/// </summary>
/// <remarks>
/// Gets the size of the body part, in bytes.
/// </remarks>
/// <value>The number of octets.</value>
public uint Octets {
get; set;
}
/// <summary>
/// Gets the MD5 hash of the content, if available.
/// </summary>
/// <remarks>
/// Gets the MD5 hash of the content, if available.
/// </remarks>
/// <value>The content md5.</value>
public string ContentMd5 {
get; set;
}
/// <summary>
/// Gets the Content-Disposition of the body part, if available.
/// </summary>
/// <remarks>
/// <para>Gets the Content-Disposition of the body part, if available.</para>
/// <note type="note">The Content-Disposition value is only retrieved if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is used when fetching
/// summary information from an <see cref="IMailFolder"/>.</note>
/// </remarks>
/// <value>The content disposition.</value>
public ContentDisposition ContentDisposition {
get; set;
}
/// <summary>
/// Gets the Content-Language of the body part, if available.
/// </summary>
/// <remarks>
/// <para>Gets the Content-Language of the body part, if available.</para>
/// <para>The Content-Language value is only retrieved if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is used when fetching
/// summary information from an <see cref="IMailFolder"/>.</para>
/// </remarks>
/// <value>The content language.</value>
public string[] ContentLanguage {
get; set;
}
/// <summary>
/// Gets the Content-Location of the body part, if available.
/// </summary>
/// <remarks>
/// <para>Gets the Content-Location of the body part, if available.</para>
/// <para>The Content-Location value is only retrieved if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is used when fetching
/// summary information from an <see cref="IMailFolder"/>.</para>
/// </remarks>
/// <value>The content location.</value>
public Uri ContentLocation {
get; set;
}
/// <summary>
/// Determines whether or not the body part is an attachment.
/// </summary>
/// <remarks>
/// <para>Determines whether or not the body part is an attachment based on the value of
/// the Content-Disposition.</para>
/// <note type="note">Since the value of the Content-Disposition header is needed, it
/// is necessary to include the <see cref="MessageSummaryItems.BodyStructure"/> flag when
/// fetching summary information from an <see cref="IMailFolder"/>.</note>
/// </remarks>
/// <value><c>true</c> if this part is an attachment; otherwise, <c>false</c>.</value>
public bool IsAttachment {
get { return ContentDisposition != null && ContentDisposition.IsAttachment; }
}
/// <summary>
/// Get the name of the file.
/// </summary>
/// <remarks>
/// <para>First checks for the "filename" parameter on the Content-Disposition header. If
/// that does not exist, then the "name" parameter on the Content-Type header is used.</para>
/// <note type="note">Since the value of the Content-Disposition header is needed, it is
/// necessary to include the <see cref="MessageSummaryItems.BodyStructure"/> flag when
/// fetching summary information from an <see cref="IMailFolder"/>.</note>
/// </remarks>
/// <value>The name of the file.</value>
public string FileName {
get {
string filename = null;
if (ContentDisposition != null)
filename = ContentDisposition.FileName;
if (filename == null)
filename = ContentType.Name;
return filename != null ? filename.Trim () : null;
}
}
/// <summary>
/// Dispatches to the specific visit method for this MIME body part.
/// </summary>
/// <remarks>
/// This default implementation for <see cref="MailKit.BodyPart"/> nodes
/// calls <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>. Override this
/// method to call into a more specific method on a derived visitor class
/// of the <see cref="MailKit.BodyPartVisitor"/> class. However, it should still
/// support unknown visitors by calling
/// <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>.
/// </remarks>
/// <param name="visitor">The visitor.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="visitor"/> is <c>null</c>.
/// </exception>
public override void Accept (BodyPartVisitor visitor)
{
if (visitor == null)
throw new ArgumentNullException (nameof (visitor));
visitor.VisitBodyPartBasic (this);
}
/// <summary>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </summary>
/// <remarks>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </remarks>
/// <param name="builder">The string builder.</param>
protected override void Encode (StringBuilder builder)
{
Encode (builder, ContentType);
builder.Append (' ');
Encode (builder, ContentId);
builder.Append (' ');
Encode (builder, ContentDescription);
builder.Append (' ');
Encode (builder, ContentTransferEncoding);
builder.Append (' ');
Encode (builder, Octets);
builder.Append (' ');
Encode (builder, ContentMd5);
builder.Append (' ');
Encode (builder, ContentDisposition);
builder.Append (' ');
Encode (builder, ContentLanguage);
builder.Append (' ');
Encode (builder, ContentLocation);
}
}
}

View File

@ -0,0 +1,276 @@
//
// BodyPartCollection.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.Linq;
using System.Collections;
using System.Collections.Generic;
using MimeKit.Utils;
namespace MailKit {
/// <summary>
/// A <see cref="BodyPart"/> collection.
/// </summary>
/// <remarks>
/// A <see cref="BodyPart"/> collection.
/// </remarks>
public class BodyPartCollection : ICollection<BodyPart>
{
readonly List<BodyPart> collection = new List<BodyPart> ();
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.BodyPartCollection"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.BodyPartCollection"/>.
/// </remarks>
public BodyPartCollection ()
{
}
/// <summary>
/// Get the number of body parts in the collection.
/// </summary>
/// <remarks>
/// Gets the number of body parts in the collection.
/// </remarks>
/// <value>The count.</value>
public int Count {
get { return collection.Count; }
}
/// <summary>
/// Get whether or not this body part collection is read only.
/// </summary>
/// <remarks>
/// Gets whether or not this body part collection is read only.
/// </remarks>
/// <value><c>true</c> if this collection is read only; otherwise, <c>false</c>.</value>
public bool IsReadOnly {
get { return false; }
}
/// <summary>
/// Add the specified body part to the collection.
/// </summary>
/// <remarks>
/// Adds the specified body part to the collection.
/// </remarks>
/// <param name="part">The body part.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="part"/> is <c>null</c>.
/// </exception>
public void Add (BodyPart part)
{
if (part == null)
throw new ArgumentNullException (nameof (part));
collection.Add (part);
}
/// <summary>
/// Clears the body part collection.
/// </summary>
/// <remarks>
/// Removes all of the body parts from the collection.
/// </remarks>
public void Clear ()
{
collection.Clear ();
}
/// <summary>
/// Checks if the collection contains the specified body part.
/// </summary>
/// <remarks>
/// Determines whether or not the collection contains the specified body part.
/// </remarks>
/// <returns><value>true</value> if the specified body part exists; otherwise <value>false</value>.</returns>
/// <param name="part">The body part.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="part"/> is <c>null</c>.
/// </exception>
public bool Contains (BodyPart part)
{
if (part == null)
throw new ArgumentNullException (nameof (part));
return collection.Contains (part);
}
/// <summary>
/// Copies all of the body parts in the collection to the specified array.
/// </summary>
/// <remarks>
/// Copies all of the body parts within the collection into the array,
/// starting at the specified array index.
/// </remarks>
/// <param name="array">The array.</param>
/// <param name="arrayIndex">The array index.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="array"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="arrayIndex"/> is out of range.
/// </exception>
public void CopyTo (BodyPart[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException (nameof (array));
if (arrayIndex < 0 || arrayIndex + Count > array.Length)
throw new ArgumentOutOfRangeException (nameof (arrayIndex));
collection.CopyTo (array, arrayIndex);
}
/// <summary>
/// Removes the specified body part.
/// </summary>
/// <remarks>
/// Removes the specified body part.
/// </remarks>
/// <returns><value>true</value> if the body part was removed; otherwise <value>false</value>.</returns>
/// <param name="part">The body part.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="part"/> is <c>null</c>.
/// </exception>
public bool Remove (BodyPart part)
{
if (part == null)
throw new ArgumentNullException (nameof (part));
return collection.Remove (part);
}
/// <summary>
/// Get the body part at the specified index.
/// </summary>
/// <remarks>
/// Gets the body part at the specified index.
/// </remarks>
/// <value>The body part at the specified index.</value>
/// <param name="index">The index.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public BodyPart this [int index] {
get {
if (index < 0 || index >= collection.Count)
throw new ArgumentOutOfRangeException (nameof (index));
return collection[index];
}
}
/// <summary>
/// Gets the index of the body part matching the specified URI.
/// </summary>
/// <remarks>
/// <para>Finds the index of the body part matching the specified URI, if it exists.</para>
/// <para>If the URI scheme is <c>"cid"</c>, then matching is performed based on the Content-Id header
/// values, otherwise the Content-Location headers are used. If the provided URI is absolute and a child
/// part's Content-Location is relative, then then the child part's Content-Location URI will be combined
/// with the value of its Content-Base header, if available, otherwise it will be combined with the
/// multipart/related part's Content-Base header in order to produce an absolute URI that can be
/// compared with the provided absolute URI.</para>
/// </remarks>
/// <returns>The index of the part matching the specified URI if found; otherwise <c>-1</c>.</returns>
/// <param name="uri">The URI of the body part.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="uri"/> is <c>null</c>.
/// </exception>
public int IndexOf (Uri uri)
{
if (uri == null)
throw new ArgumentNullException (nameof (uri));
bool cid = uri.IsAbsoluteUri && uri.Scheme.ToLowerInvariant () == "cid";
for (int index = 0; index < Count; index++) {
var bodyPart = this[index] as BodyPartBasic;
if (bodyPart == null)
continue;
if (uri.IsAbsoluteUri) {
if (cid) {
if (!string.IsNullOrEmpty (bodyPart.ContentId)) {
// Note: we might have a Content-Id in the form "<id@domain.com>", so attempt to decode it
var id = MimeUtils.EnumerateReferences (bodyPart.ContentId).FirstOrDefault () ?? bodyPart.ContentId;
if (id == uri.AbsolutePath)
return index;
}
} else if (bodyPart.ContentLocation != null) {
if (!bodyPart.ContentLocation.IsAbsoluteUri)
continue;
if (bodyPart.ContentLocation == uri)
return index;
}
} else if (bodyPart.ContentLocation == uri) {
return index;
}
}
return -1;
}
#region IEnumerable implementation
/// <summary>
/// Get the body part enumerator.
/// </summary>
/// <remarks>
/// Gets the body part enumerator.
/// </remarks>
/// <returns>The enumerator.</returns>
public IEnumerator<BodyPart> GetEnumerator ()
{
return collection.GetEnumerator ();
}
#endregion
#region IEnumerable implementation
/// <summary>
/// Get the body part enumerator.
/// </summary>
/// <remarks>
/// Gets the body part enumerator.
/// </remarks>
/// <returns>The enumerator.</returns>
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
#endregion
}
}

View File

@ -0,0 +1,124 @@
//
// BodyPartMessage.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.Text;
namespace MailKit {
/// <summary>
/// A message/rfc822 body part.
/// </summary>
/// <remarks>
/// Represents a message/rfc822 body part.
/// </remarks>
public class BodyPartMessage : BodyPartBasic
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.BodyPartMessage"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="BodyPartMessage"/>.
/// </remarks>
public BodyPartMessage ()
{
}
/// <summary>
/// Gets the envelope of the message, if available.
/// </summary>
/// <remarks>
/// Gets the envelope of the message, if available.
/// </remarks>
/// <value>The envelope.</value>
public Envelope Envelope {
get; set;
}
/// <summary>
/// Gets the body structure of the message.
/// </summary>
/// <remarks>
/// Gets the body structure of the message.
/// </remarks>
/// <value>The body structure.</value>
public BodyPart Body {
get; set;
}
/// <summary>
/// Gets the length of the message, in lines.
/// </summary>
/// <remarks>
/// Gets the length of the message, in lines.
/// </remarks>
/// <value>The number of lines.</value>
public uint Lines {
get; set;
}
/// <summary>
/// Dispatches to the specific visit method for this MIME body part.
/// </summary>
/// <remarks>
/// This default implementation for <see cref="MailKit.BodyPart"/> nodes
/// calls <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>. Override this
/// method to call into a more specific method on a derived visitor class
/// of the <see cref="MailKit.BodyPartVisitor"/> class. However, it should still
/// support unknown visitors by calling
/// <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>.
/// </remarks>
/// <param name="visitor">The visitor.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="visitor"/> is <c>null</c>.
/// </exception>
public override void Accept (BodyPartVisitor visitor)
{
if (visitor == null)
throw new ArgumentNullException (nameof (visitor));
visitor.VisitBodyPartMessage (this);
}
/// <summary>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </summary>
/// <remarks>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </remarks>
/// <param name="builder">The string builder.</param>
protected override void Encode (StringBuilder builder)
{
base.Encode (builder);
builder.Append (' ');
Encode (builder, Envelope);
builder.Append (' ');
Encode (builder, Body);
builder.Append (' ');
Encode (builder, Lines);
}
}
}

View File

@ -0,0 +1,141 @@
//
// BodyPartMultipart.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.Text;
using MimeKit;
namespace MailKit {
/// <summary>
/// A multipart body part.
/// </summary>
/// <remarks>
/// A multipart body part.
/// </remarks>
public class BodyPartMultipart : BodyPart
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.BodyPartMultipart"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="BodyPartMultipart"/>.
/// </remarks>
public BodyPartMultipart ()
{
BodyParts = new BodyPartCollection ();
}
/// <summary>
/// Gets the child body parts.
/// </summary>
/// <remarks>
/// Gets the child body parts.
/// </remarks>
/// <value>The child body parts.</value>
public BodyPartCollection BodyParts {
get; private set;
}
/// <summary>
/// Gets the Content-Disposition of the body part, if available.
/// </summary>
/// <remarks>
/// Gets the Content-Disposition of the body part, if available.
/// </remarks>
/// <value>The content disposition.</value>
public ContentDisposition ContentDisposition {
get; set;
}
/// <summary>
/// Gets the Content-Language of the body part, if available.
/// </summary>
/// <remarks>
/// Gets the Content-Language of the body part, if available.
/// </remarks>
/// <value>The content language.</value>
public string[] ContentLanguage {
get; set;
}
/// <summary>
/// Gets the Content-Location of the body part, if available.
/// </summary>
/// <remarks>
/// Gets the Content-Location of the body part, if available.
/// </remarks>
/// <value>The content location.</value>
public Uri ContentLocation {
get; set;
}
/// <summary>
/// Dispatches to the specific visit method for this MIME body part.
/// </summary>
/// <remarks>
/// This default implementation for <see cref="MailKit.BodyPart"/> nodes
/// calls <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>. Override this
/// method to call into a more specific method on a derived visitor class
/// of the <see cref="MailKit.BodyPartVisitor"/> class. However, it should still
/// support unknown visitors by calling
/// <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>.
/// </remarks>
/// <param name="visitor">The visitor.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="visitor"/> is <c>null</c>.
/// </exception>
public override void Accept (BodyPartVisitor visitor)
{
if (visitor == null)
throw new ArgumentNullException (nameof (visitor));
visitor.VisitBodyPartMultipart (this);
}
/// <summary>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </summary>
/// <remarks>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </remarks>
/// <param name="builder">The string builder.</param>
protected override void Encode (StringBuilder builder)
{
Encode (builder, BodyParts);
builder.Append (' ');
Encode (builder, ContentType.MediaSubtype);
builder.Append (' ');
Encode (builder, ContentType.Parameters);
builder.Append (' ');
Encode (builder, ContentDisposition);
builder.Append (' ');
Encode (builder, ContentLanguage);
builder.Append (' ');
Encode (builder, ContentLocation);
}
}
}

123
src/MailKit/BodyPartText.cs Normal file
View File

@ -0,0 +1,123 @@
//
// BodyPartText.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.Text;
namespace MailKit {
/// <summary>
/// A textual body part.
/// </summary>
/// <remarks>
/// Represents any body part with a media type of "text".
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
public class BodyPartText : BodyPartBasic
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.BodyPartText"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="BodyPartText"/>.
/// </remarks>
public BodyPartText ()
{
}
/// <summary>
/// Gets whether or not this text part contains plain text.
/// </summary>
/// <remarks>
/// Checks whether or not the text part's Content-Type is text/plain.
/// </remarks>
/// <value><c>true</c> if the text is html; otherwise, <c>false</c>.</value>
public bool IsPlain {
get { return ContentType.IsMimeType ("text", "plain"); }
}
/// <summary>
/// Gets whether or not this text part contains HTML.
/// </summary>
/// <remarks>
/// Checks whether or not the text part's Content-Type is text/html.
/// </remarks>
/// <value><c>true</c> if the text is html; otherwise, <c>false</c>.</value>
public bool IsHtml {
get { return ContentType.IsMimeType ("text", "html"); }
}
/// <summary>
/// Gets the length of the text, in lines.
/// </summary>
/// <remarks>
/// Gets the length of the text, in lines.
/// </remarks>
/// <value>The number of lines.</value>
public uint Lines {
get; set;
}
/// <summary>
/// Dispatches to the specific visit method for this MIME body part.
/// </summary>
/// <remarks>
/// This default implementation for <see cref="MailKit.BodyPart"/> nodes
/// calls <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>. Override this
/// method to call into a more specific method on a derived visitor class
/// of the <see cref="MailKit.BodyPartVisitor"/> class. However, it should still
/// support unknown visitors by calling
/// <see cref="MailKit.BodyPartVisitor.VisitBodyPart"/>.
/// </remarks>
/// <param name="visitor">The visitor.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="visitor"/> is <c>null</c>.
/// </exception>
public override void Accept (BodyPartVisitor visitor)
{
if (visitor == null)
throw new ArgumentNullException (nameof (visitor));
visitor.VisitBodyPartText (this);
}
/// <summary>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </summary>
/// <remarks>
/// Encodes the <see cref="BodyPart"/> into the <see cref="System.Text.StringBuilder"/>.
/// </remarks>
/// <param name="builder">The string builder.</param>
protected override void Encode (StringBuilder builder)
{
base.Encode (builder);
builder.Append (' ');
Encode (builder, Lines);
}
}
}

View File

@ -0,0 +1,137 @@
//
// BodyPartVisitor.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.
//
namespace MailKit {
/// <summary>
/// Represents a visitor for a tree of MIME body parts.
/// </summary>
/// <remarks>
/// This class is designed to be inherited to create more specialized classes whose
/// functionality requires traversing, examining or copying a tree of MIME body parts.
/// </remarks>
public abstract class BodyPartVisitor
{
/// <summary>
/// Dispatches the entity to one of the more specialized visit methods in this class.
/// </summary>
/// <remarks>
/// Dispatches the entity to one of the more specialized visit methods in this class.
/// </remarks>
/// <param name="body">The MIME body part.</param>
public virtual void Visit (BodyPart body)
{
if (body != null)
body.Accept (this);
}
/// <summary>
/// Visit the abstract MIME body part.
/// </summary>
/// <remarks>
/// Visits the abstract MIME body part.
/// </remarks>
/// <param name="entity">The MIME body part.</param>
protected internal virtual void VisitBodyPart (BodyPart entity)
{
}
/// <summary>
/// Visit the basic MIME body part.
/// </summary>
/// <remarks>
/// Visits the basic MIME body part.
/// </remarks>
/// <param name="entity">The basic MIME body part.</param>
protected internal virtual void VisitBodyPartBasic (BodyPartBasic entity)
{
VisitBodyPart (entity);
}
/// <summary>
/// Visit the message contained within a message/rfc822 or message/news MIME entity.
/// </summary>
/// <remarks>
/// Visits the message contained within a message/rfc822 or message/news MIME entity.
/// </remarks>
/// <param name="message">The body part representing the message/rfc822 message.</param>
protected virtual void VisitMessage (BodyPart message)
{
if (message != null)
message.Accept (this);
}
/// <summary>
/// Visit the message/rfc822 or message/news MIME entity.
/// </summary>
/// <remarks>
/// Visits the message/rfc822 or message/news MIME entity.
/// </remarks>
/// <param name="entity">The message/rfc822 or message/news body part.</param>
protected internal virtual void VisitBodyPartMessage (BodyPartMessage entity)
{
VisitBodyPartBasic (entity);
VisitMessage (entity.Body);
}
/// <summary>
/// Visit the children of a <see cref="MailKit.BodyPartMultipart"/>.
/// </summary>
/// <remarks>
/// Visits the children of a <see cref="MailKit.BodyPartMultipart"/>.
/// </remarks>
/// <param name="multipart">The multipart.</param>
protected virtual void VisitChildren (BodyPartMultipart multipart)
{
for (int i = 0; i < multipart.BodyParts.Count; i++)
multipart.BodyParts[i].Accept (this);
}
/// <summary>
/// Visit the abstract multipart MIME entity.
/// </summary>
/// <remarks>
/// Visits the abstract multipart MIME entity.
/// </remarks>
/// <param name="multipart">The multipart body part.</param>
protected internal virtual void VisitBodyPartMultipart (BodyPartMultipart multipart)
{
VisitBodyPart (multipart);
VisitChildren (multipart);
}
/// <summary>
/// Visit the text-based MIME part entity.
/// </summary>
/// <remarks>
/// Visits the text-based MIME part entity.
/// </remarks>
/// <param name="entity">The text-based body part.</param>
protected internal virtual void VisitBodyPartText (BodyPartText entity)
{
VisitBodyPartBasic (entity);
}
}
}

View File

@ -0,0 +1,102 @@
//
// CommandException.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;
#if SERIALIZABLE
using System.Security;
using System.Runtime.Serialization;
#endif
namespace MailKit {
/// <summary>
/// The exception that is thrown when there is a command error.
/// </summary>
/// <remarks>
/// A <see cref="CommandException"/> can be thrown by any of the various client
/// methods in MailKit. Unlike a <see cref="ProtocolException"/>, a
/// <see cref="CommandException"/> is typically non-fatal (meaning that it does
/// not force the client to disconnect).
/// </remarks>
#if SERIALIZABLE
[Serializable]
#endif
public abstract class CommandException : Exception
{
#if SERIALIZABLE
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.CommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="CommandException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
[SecuritySafeCritical]
protected CommandException (SerializationInfo info, StreamingContext context) : base (info, context)
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.CommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="CommandException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
/// <param name="innerException">An inner exception.</param>
protected CommandException (string message, Exception innerException) : base (message, innerException)
{
HelpLink = "https://github.com/jstedfast/MailKit/blob/master/FAQ.md#ProtocolLog";
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.CommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="CommandException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
protected CommandException (string message) : base (message)
{
HelpLink = "https://github.com/jstedfast/MailKit/blob/master/FAQ.md#ProtocolLog";
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.CommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="CommandException"/>.
/// </remarks>
protected CommandException ()
{
HelpLink = "https://github.com/jstedfast/MailKit/blob/master/FAQ.md#ProtocolLog";
}
}
}

View File

@ -0,0 +1,435 @@
//
// CompressedStream.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.Threading;
using System.Threading.Tasks;
using Org.BouncyCastle.Utilities.Zlib;
namespace MailKit {
/// <summary>
/// A compressed stream.
/// </summary>
class CompressedStream : Stream
{
readonly ZStream zIn, zOut;
bool eos, disposed;
public CompressedStream (Stream innerStream)
{
InnerStream = innerStream;
zOut = new ZStream ();
zOut.deflateInit (5, true);
zOut.next_out = new byte[4096];
zIn = new ZStream ();
zIn.inflateInit (true);
zIn.next_in = new byte[4096];
}
/// <summary>
/// Gets the inner stream.
/// </summary>
/// <value>The inner stream.</value>
public Stream InnerStream {
get; private set;
}
/// <summary>
/// Gets whether the stream supports reading.
/// </summary>
/// <value><c>true</c> if the stream supports reading; otherwise, <c>false</c>.</value>
public override bool CanRead {
get { return InnerStream.CanRead; }
}
/// <summary>
/// Gets whether the stream supports writing.
/// </summary>
/// <value><c>true</c> if the stream supports writing; otherwise, <c>false</c>.</value>
public override bool CanWrite {
get { return InnerStream.CanWrite; }
}
/// <summary>
/// Gets whether the stream supports seeking.
/// </summary>
/// <value><c>true</c> if the stream supports seeking; otherwise, <c>false</c>.</value>
public override bool CanSeek {
get { return false; }
}
/// <summary>
/// Gets whether the stream supports I/O timeouts.
/// </summary>
/// <value><c>true</c> if the stream supports I/O timeouts; otherwise, <c>false</c>.</value>
public override bool CanTimeout {
get { return InnerStream.CanTimeout; }
}
/// <summary>
/// Gets or sets a value, in miliseconds, that determines how long the stream will attempt to read before timing out.
/// </summary>
/// <returns>A value, in miliseconds, that determines how long the stream will attempt to read before timing out.</returns>
/// <value>The read timeout.</value>
public override int ReadTimeout {
get { return InnerStream.ReadTimeout; }
set { InnerStream.ReadTimeout = value; }
}
/// <summary>
/// Gets or sets a value, in miliseconds, that determines how long the stream will attempt to write before timing out.
/// </summary>
/// <returns>A value, in miliseconds, that determines how long the stream will attempt to write before timing out.</returns>
/// <value>The write timeout.</value>
public override int WriteTimeout {
get { return InnerStream.WriteTimeout; }
set { InnerStream.WriteTimeout = value; }
}
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
/// <returns>The current position within the stream.</returns>
/// <value>The position of the stream.</value>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
public override long Position {
get { throw new NotSupportedException (); }
set { throw new NotSupportedException (); }
}
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
/// <returns>A long value representing the length of the stream in bytes.</returns>
/// <value>The length of the stream.</value>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
public override long Length {
get { throw new NotSupportedException (); }
}
static void ValidateArguments (byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException (nameof (buffer));
if (offset < 0 || offset > buffer.Length)
throw new ArgumentOutOfRangeException (nameof (offset));
if (count < 0 || count > (buffer.Length - offset))
throw new ArgumentOutOfRangeException (nameof (count));
}
void CheckDisposed ()
{
if (disposed)
throw new ObjectDisposedException (nameof (CompressedStream));
}
async Task<int> ReadAsync (byte[] buffer, int offset, int count, bool doAsync, CancellationToken cancellationToken)
{
CheckDisposed ();
ValidateArguments (buffer, offset, count);
if (count == 0)
return 0;
zIn.next_out = buffer;
zIn.next_out_index = offset;
zIn.avail_out = count;
do {
if (zIn.avail_in == 0 && !eos) {
cancellationToken.ThrowIfCancellationRequested ();
if (doAsync)
zIn.avail_in = await InnerStream.ReadAsync (zIn.next_in, 0, zIn.next_in.Length, cancellationToken).ConfigureAwait (false);
else
zIn.avail_in = InnerStream.Read (zIn.next_in, 0, zIn.next_in.Length);
eos = zIn.avail_in == 0;
zIn.next_in_index = 0;
}
int retval = zIn.inflate (JZlib.Z_FULL_FLUSH);
if (retval == JZlib.Z_STREAM_END)
break;
if (eos && retval == JZlib.Z_BUF_ERROR)
return 0;
if (retval != JZlib.Z_OK)
throw new IOException ("Error inflating: " + zIn.msg);
} while (zIn.avail_out == count);
return count - zIn.avail_out;
}
/// <summary>
/// Reads a sequence of bytes from the stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many
/// bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <param name="count">The number of bytes to read.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override int Read (byte[] buffer, int offset, int count)
{
return ReadAsync (buffer, offset, count, false, CancellationToken.None).GetAwaiter ().GetResult ();
}
/// <summary>
/// Reads a sequence of bytes from the stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many
/// bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <param name="count">The number of bytes to read.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return ReadAsync (buffer, offset, count, true, cancellationToken);
}
async Task WriteAsync (byte[] buffer, int offset, int count, bool doAsync, CancellationToken cancellationToken)
{
CheckDisposed ();
ValidateArguments (buffer, offset, count);
if (count == 0)
return;
zOut.next_in = buffer;
zOut.next_in_index = offset;
zOut.avail_in = count;
do {
cancellationToken.ThrowIfCancellationRequested ();
zOut.avail_out = zOut.next_out.Length;
zOut.next_out_index = 0;
if (zOut.deflate (JZlib.Z_FULL_FLUSH) != JZlib.Z_OK)
throw new IOException ("Error deflating: " + zOut.msg);
if (doAsync)
await InnerStream.WriteAsync (zOut.next_out, 0, zOut.next_out.Length - zOut.avail_out, cancellationToken).ConfigureAwait (false);
else
InnerStream.Write (zOut.next_out, 0, zOut.next_out.Length - zOut.avail_out);
} while (zOut.avail_in > 0 || zOut.avail_out == 0);
}
/// <summary>
/// Writes a sequence of bytes to the stream and advances the current
/// position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">The buffer to write.</param>
/// <param name="offset">The offset of the first byte to write.</param>
/// <param name="count">The number of bytes to write.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override void Write (byte[] buffer, int offset, int count)
{
WriteAsync (buffer, offset, count, false, CancellationToken.None).GetAwaiter ().GetResult ();
}
/// <summary>
/// Writes a sequence of bytes to the stream and advances the current
/// position within this stream by the number of bytes written.
/// </summary>
/// <returns>A task that represents the asynchronous write operation.</returns>
/// <param name="buffer">The buffer to write.</param>
/// <param name="offset">The offset of the first byte to write.</param>
/// <param name="count">The number of bytes to write.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return WriteAsync (buffer, offset, count, true, cancellationToken);
}
/// <summary>
/// Clears all output buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override void Flush ()
{
CheckDisposed ();
InnerStream.Flush ();
}
/// <summary>
/// Clears all output buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
/// <returns>A task that represents the asynchronous flush operation.</returns>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override Task FlushAsync (CancellationToken cancellationToken)
{
CheckDisposed ();
return InnerStream.FlushAsync (cancellationToken);
}
/// <summary>
/// Sets the position within the current stream.
/// </summary>
/// <returns>The new position within the stream.</returns>
/// <param name="offset">The offset into the stream relative to the <paramref name="origin"/>.</param>
/// <param name="origin">The origin to seek from.</param>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
/// <summary>
/// Sets the length of the stream.
/// </summary>
/// <param name="value">The desired length of the stream in bytes.</param>
/// <exception cref="System.NotSupportedException">
/// The stream does not support setting the length.
/// </exception>
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="CompressedStream"/> and
/// optionally releases the managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
/// <c>false</c> to release only the unmanaged resources.</param>
protected override void Dispose (bool disposing)
{
if (disposing && !disposed) {
InnerStream.Dispose ();
disposed = true;
zOut.free ();
zIn.free ();
}
base.Dispose (disposing);
}
}
}

View File

@ -0,0 +1,88 @@
//
// ConnectedEventArgs.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 MailKit.Security;
namespace MailKit
{
/// <summary>
/// Connected event arguments.
/// </summary>
/// <remarks>
/// When a <see cref="IMailService"/> is connected, it will emit a
/// <see cref=" IMailService.Connected"/> event.
/// </remarks>
public class ConnectedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.ConnectedEventArgs"/> class.
/// </summary>
/// <param name="host">The name of the host that the client connected to.</param>
/// <param name="port">The port that the client connected to on the remote host.</param>
/// <param name="options">The SSL/TLS options that were used when connecting to the remote host.</param>
public ConnectedEventArgs (string host, int port, SecureSocketOptions options)
{
Options = options;
Host = host;
Port = port;
}
/// <summary>
/// Get the name of the remote host.
/// </summary>
/// <remarks>
/// Gets the name of the remote host.
/// </remarks>
/// <value>The host name of the server.</value>
public string Host {
get; private set;
}
/// <summary>
/// Get the port.
/// </summary>
/// <remarks>
/// Gets the port.
/// </remarks>
/// <value>The port.</value>
public int Port {
get; private set;
}
/// <summary>
/// Get the SSL/TLS options.
/// </summary>
/// <remarks>
/// Gets the SSL/TLS options.
/// </remarks>
/// <value>The SSL/TLS options.</value>
public SecureSocketOptions Options {
get; private set;
}
}
}

View File

@ -0,0 +1,61 @@
//
// DeliveryStatusNotification.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;
namespace MailKit {
/// <summary>
/// Delivery status notification types.
/// </summary>
/// <remarks>
/// A set of flags that may be bitwise-or'd together to specify
/// when a delivery status notification should be sent for a
/// particlar recipient.
/// </remarks>
[Flags]
public enum DeliveryStatusNotification {
/// <summary>
/// Never send delivery status notifications.
/// </summary>
Never = 0,
/// <summary>
/// Send a notification on successful delivery to the recipient.
/// </summary>
Success = (1 << 0),
/// <summary>
/// Send a notification on failure to deliver to the recipient.
/// </summary>
Failure = (1 << 1),
/// <summary>
/// Send a notification when the delivery to the recipient has
/// been delayed for an unusual amount of time.
/// </summary>
Delay = (1 << 2)
}
}

View File

@ -0,0 +1,54 @@
//
// DeliveryStatusNotificationReturnType.cs
//
// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
//
// Copyright (c) 2013-2019 .NET Foundation and Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
namespace MailKit.Net.Smtp
{
/// <summary>
/// Delivery status notification type.
/// </summary>
/// <remarks>
/// The delivery status notification type specifies whether or not
/// the full message should be included in any failed DSN issued for
/// a message transmission as opposed to just the headers.
/// </remarks>
public enum DeliveryStatusNotificationType
{
/// <summary>
/// The return type is unspecified, allowing the server to choose.
/// </summary>
Unspecified,
/// <summary>
/// The full message should be included in any failed delivery status notification issued by the server.
/// </summary>
Full,
/// <summary>
/// Only the headers should be included in any failed delivery status notification issued by the server.
/// </summary>
HeadersOnly,
}
}

View File

@ -0,0 +1,70 @@
//
// DisconnectedEventArgs.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 MailKit.Security;
namespace MailKit
{
/// <summary>
/// Disconnected event arguments.
/// </summary>
/// <remarks>
/// When a <see cref="IMailService"/> gets disconnected, it will emit a
/// <see cref=" IMailService.Disconnected"/> event.
/// </remarks>
public class DisconnectedEventArgs : ConnectedEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.DisconnectedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.DisconnectedEventArgs"/> class.
/// </remarks>
/// <param name="host">The name of the host that the client was connected to.</param>
/// <param name="port">The port that the client was connected to.</param>
/// <param name="options">The SSL/TLS options that were used by the client.</param>
/// <param name="requested">If <c>true</c>, the <see cref="IMailService"/> was disconnected via the
/// <see cref="IMailService.Disconnect(bool, System.Threading.CancellationToken)"/> method.</param>
public DisconnectedEventArgs (string host, int port, SecureSocketOptions options, bool requested) : base (host, port, options)
{
IsRequested = requested;
}
/// <summary>
/// Get whether or not the service was explicitly asked to disconnect.
/// </summary>
/// <remarks>
/// If the <see cref="IMailService"/> was disconnected via the
/// <see cref="IMailService.Disconnect(bool, System.Threading.CancellationToken)"/> method, then
/// the value of <see cref="IsRequested"/> will be <c>true</c>. If the connection was unexpectedly
/// dropped, then the value will be <c>false</c>.
/// </remarks>
/// <value><c>true</c> if the disconnect was explicitly requested; otherwise, <c>false</c>.</value>
public bool IsRequested {
get; private set;
}
}
}

395
src/MailKit/DuplexStream.cs Normal file
View File

@ -0,0 +1,395 @@
//
// DuplexStream.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.Threading;
using System.Threading.Tasks;
namespace MailKit {
/// <summary>
/// A duplex stream.
/// </summary>
class DuplexStream : Stream
{
bool disposed;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.DuplexStream"/> class.
/// </summary>
/// <param name="istream">The stream to use for input.</param>
/// <param name="ostream">The stream to use for output.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="istream"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="ostream"/> is <c>null</c>.</para>
/// </exception>
public DuplexStream (Stream istream, Stream ostream)
{
if (istream == null)
throw new ArgumentNullException (nameof (istream));
if (ostream == null)
throw new ArgumentNullException (nameof (ostream));
InputStream = istream;
OutputStream = ostream;
}
/// <summary>
/// Gets the input stream.
/// </summary>
/// <value>The input stream.</value>
public Stream InputStream {
get; private set;
}
/// <summary>
/// Gets the output stream.
/// </summary>
/// <value>The output stream.</value>
public Stream OutputStream {
get; private set;
}
/// <summary>
/// Gets whether the stream supports reading.
/// </summary>
/// <value><c>true</c> if the stream supports reading; otherwise, <c>false</c>.</value>
public override bool CanRead {
get { return true; }
}
/// <summary>
/// Gets whether the stream supports writing.
/// </summary>
/// <value><c>true</c> if the stream supports writing; otherwise, <c>false</c>.</value>
public override bool CanWrite {
get { return true; }
}
/// <summary>
/// Gets whether the stream supports seeking.
/// </summary>
/// <value><c>true</c> if the stream supports seeking; otherwise, <c>false</c>.</value>
public override bool CanSeek {
get { return false; }
}
/// <summary>
/// Gets whether the stream supports I/O timeouts.
/// </summary>
/// <value><c>true</c> if the stream supports I/O timeouts; otherwise, <c>false</c>.</value>
public override bool CanTimeout {
get { return InputStream.CanTimeout && OutputStream.CanTimeout; }
}
/// <summary>
/// Gets or sets a value, in miliseconds, that determines how long the stream will attempt to read before timing out.
/// </summary>
/// <returns>A value, in miliseconds, that determines how long the stream will attempt to read before timing out.</returns>
/// <value>The read timeout.</value>
public override int ReadTimeout {
get { return InputStream.ReadTimeout; }
set { InputStream.ReadTimeout = value; }
}
/// <summary>
/// Gets or sets a value, in miliseconds, that determines how long the stream will attempt to write before timing out.
/// </summary>
/// <returns>A value, in miliseconds, that determines how long the stream will attempt to write before timing out.</returns>
/// <value>The write timeout.</value>
public override int WriteTimeout {
get { return OutputStream.WriteTimeout; }
set { OutputStream.WriteTimeout = value; }
}
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
/// <returns>The current position within the stream.</returns>
/// <value>The position of the stream.</value>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
public override long Position {
get { throw new NotSupportedException (); }
set { throw new NotSupportedException (); }
}
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
/// <returns>A long value representing the length of the stream in bytes.</returns>
/// <value>The length of the stream.</value>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
public override long Length {
get { throw new NotSupportedException (); }
}
static void ValidateArguments (byte[] buffer, int offset, int count)
{
if (buffer == null)
throw new ArgumentNullException (nameof (buffer));
if (offset < 0 || offset > buffer.Length)
throw new ArgumentOutOfRangeException (nameof (offset));
if (count < 0 || count > (buffer.Length - offset))
throw new ArgumentOutOfRangeException (nameof (count));
}
void CheckDisposed ()
{
if (disposed)
throw new ObjectDisposedException (nameof (DuplexStream));
}
/// <summary>
/// Reads a sequence of bytes from the stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many
/// bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <param name="count">The number of bytes to read.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override int Read (byte[] buffer, int offset, int count)
{
CheckDisposed ();
ValidateArguments (buffer, offset, count);
return InputStream.Read (buffer, offset, count);
}
/// <summary>
/// Reads a sequence of bytes from the stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many
/// bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <param name="count">The number of bytes to read.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
CheckDisposed ();
ValidateArguments (buffer, offset, count);
return InputStream.ReadAsync (buffer, offset, count, cancellationToken);
}
/// <summary>
/// Writes a sequence of bytes to the stream and advances the current
/// position within this stream by the number of bytes written.
/// </summary>
/// <param name="buffer">The buffer to write.</param>
/// <param name="offset">The offset of the first byte to write.</param>
/// <param name="count">The number of bytes to write.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override void Write (byte[] buffer, int offset, int count)
{
CheckDisposed ();
ValidateArguments (buffer, offset, count);
OutputStream.Write (buffer, offset, count);
}
/// <summary>
/// Writes a sequence of bytes to the stream and advances the current
/// position within this stream by the number of bytes written.
/// </summary>
/// <returns>A task that represents the asynchronous write operation.</returns>
/// <param name="buffer">The buffer to write.</param>
/// <param name="offset">The offset of the first byte to write.</param>
/// <param name="count">The number of bytes to write.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
CheckDisposed ();
ValidateArguments (buffer, offset, count);
return OutputStream.WriteAsync (buffer, offset, count, cancellationToken);
}
/// <summary>
/// Clears all output buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override void Flush ()
{
CheckDisposed ();
OutputStream.Flush ();
}
/// <summary>
/// Clears all output buffers for this stream and causes any buffered data to be written
/// to the underlying device.
/// </summary>
/// <returns>A task that represents the asynchronous flush operation.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The stream has been disposed.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The stream does not support writing.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
public override Task FlushAsync (CancellationToken cancellationToken)
{
CheckDisposed ();
return OutputStream.FlushAsync (cancellationToken);
}
/// <summary>
/// Sets the position within the current stream.
/// </summary>
/// <returns>The new position within the stream.</returns>
/// <param name="offset">The offset into the stream relative to the <paramref name="origin"/>.</param>
/// <param name="origin">The origin to seek from.</param>
/// <exception cref="System.NotSupportedException">
/// The stream does not support seeking.
/// </exception>
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
/// <summary>
/// Sets the length of the stream.
/// </summary>
/// <param name="value">The desired length of the stream in bytes.</param>
/// <exception cref="System.NotSupportedException">
/// The stream does not support setting the length.
/// </exception>
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
/// <summary>
/// Releases the unmanaged resources used by the <see cref="DuplexStream"/> and
/// optionally releases the managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
/// <c>false</c> to release only the unmanaged resources.</param>
protected override void Dispose (bool disposing)
{
if (disposing && !disposed) {
OutputStream.Dispose ();
InputStream.Dispose ();
disposed = true;
}
base.Dispose (disposing);
}
}
}

592
src/MailKit/Envelope.cs Normal file
View File

@ -0,0 +1,592 @@
//
// Envelope.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.Text;
using System.Linq;
using System.Collections.Generic;
using MimeKit;
using MimeKit.Utils;
namespace MailKit {
/// <summary>
/// A message envelope containing a brief summary of the message.
/// </summary>
/// <remarks>
/// The envelope of a message contains information such as the
/// date the message was sent, the subject of the message,
/// the sender of the message, who the message was sent to,
/// which message(s) the message may be in reply to,
/// and the message id.
/// </remarks>
public class Envelope
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Envelope"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="Envelope"/>.
/// </remarks>
public Envelope ()
{
From = new InternetAddressList ();
Sender = new InternetAddressList ();
ReplyTo = new InternetAddressList ();
To = new InternetAddressList ();
Cc = new InternetAddressList ();
Bcc = new InternetAddressList ();
}
/// <summary>
/// Gets the address(es) that the message is from.
/// </summary>
/// <remarks>
/// Gets the address(es) that the message is from.
/// </remarks>
/// <value>The address(es) that the message is from.</value>
public InternetAddressList From {
get; private set;
}
/// <summary>
/// Gets the actual sender(s) of the message.
/// </summary>
/// <remarks>
/// The senders may differ from the addresses in <see cref="From"/> if
/// the message was sent by someone on behalf of someone else.
/// </remarks>
/// <value>The actual sender(s) of the message.</value>
public InternetAddressList Sender {
get; private set;
}
/// <summary>
/// Gets the address(es) that replies should be sent to.
/// </summary>
/// <remarks>
/// The senders of the message may prefer that replies are sent
/// somewhere other than the address they used to send the message.
/// </remarks>
/// <value>The address(es) that replies should be sent to.</value>
public InternetAddressList ReplyTo {
get; private set;
}
/// <summary>
/// Gets the list of addresses that the message was sent to.
/// </summary>
/// <remarks>
/// Gets the list of addresses that the message was sent to.
/// </remarks>
/// <value>The address(es) that the message was sent to.</value>
public InternetAddressList To {
get; private set;
}
/// <summary>
/// Gets the list of addresses that the message was carbon-copied to.
/// </summary>
/// <remarks>
/// Gets the list of addresses that the message was carbon-copied to.
/// </remarks>
/// <value>The address(es) that the message was carbon-copied to.</value>
public InternetAddressList Cc {
get; private set;
}
/// <summary>
/// Gets the list of addresses that the message was blind-carbon-copied to.
/// </summary>
/// <remarks>
/// Gets the list of addresses that the message was blind-carbon-copied to.
/// </remarks>
/// <value>The address(es) that the message was carbon-copied to.</value>
public InternetAddressList Bcc {
get; private set;
}
/// <summary>
/// The Message-Id that the message is replying to.
/// </summary>
/// <remarks>
/// The Message-Id that the message is replying to.
/// </remarks>
/// <value>The Message-Id that the message is replying to.</value>
public string InReplyTo {
get; set;
}
/// <summary>
/// Gets the date that the message was sent on, if available.
/// </summary>
/// <remarks>
/// Gets the date that the message was sent on, if available.
/// </remarks>
/// <value>The date the message was sent.</value>
public DateTimeOffset? Date {
get; set;
}
/// <summary>
/// Gets the ID of the message, if available.
/// </summary>
/// <remarks>
/// Gets the ID of the message, if available.
/// </remarks>
/// <value>The message identifier.</value>
public string MessageId {
get; set;
}
/// <summary>
/// Gets the subject of the message.
/// </summary>
/// <remarks>
/// Gets the subject of the message.
/// </remarks>
/// <value>The subject.</value>
public string Subject {
get; set;
}
static void EncodeMailbox (StringBuilder builder, MailboxAddress mailbox)
{
builder.Append ('(');
if (mailbox.Name != null)
builder.AppendFormat ("{0} ", MimeUtils.Quote (mailbox.Name));
else
builder.Append ("NIL ");
if (mailbox.Route.Count != 0)
builder.AppendFormat ("\"{0}\" ", mailbox.Route);
else
builder.Append ("NIL ");
int at = mailbox.Address.LastIndexOf ('@');
if (at >= 0) {
var domain = mailbox.Address.Substring (at + 1);
var user = mailbox.Address.Substring (0, at);
builder.AppendFormat ("{0} {1}", MimeUtils.Quote (user), MimeUtils.Quote (domain));
} else {
builder.AppendFormat ("{0} \"localhost\"", MimeUtils.Quote (mailbox.Address));
}
builder.Append (')');
}
static void EncodeInternetAddressListAddresses (StringBuilder builder, InternetAddressList addresses)
{
foreach (var addr in addresses) {
var mailbox = addr as MailboxAddress;
var group = addr as GroupAddress;
if (mailbox != null)
EncodeMailbox (builder, mailbox);
else if (group != null)
EncodeGroup (builder, group);
}
}
static void EncodeGroup (StringBuilder builder, GroupAddress group)
{
builder.AppendFormat ("(NIL NIL {0} NIL)", MimeUtils.Quote (group.Name));
EncodeInternetAddressListAddresses (builder, group.Members);
builder.Append ("(NIL NIL NIL NIL)");
}
static void EncodeAddressList (StringBuilder builder, InternetAddressList list)
{
builder.Append ('(');
EncodeInternetAddressListAddresses (builder, list);
builder.Append (')');
}
internal void Encode (StringBuilder builder)
{
builder.Append ('(');
if (Date.HasValue)
builder.AppendFormat ("\"{0}\" ", DateUtils.FormatDate (Date.Value));
else
builder.Append ("NIL ");
if (Subject != null)
builder.AppendFormat ("{0} ", MimeUtils.Quote (Subject));
else
builder.Append ("NIL ");
if (From.Count > 0) {
EncodeAddressList (builder, From);
builder.Append (' ');
} else {
builder.Append ("NIL ");
}
if (Sender.Count > 0) {
EncodeAddressList (builder, Sender);
builder.Append (' ');
} else {
builder.Append ("NIL ");
}
if (ReplyTo.Count > 0) {
EncodeAddressList (builder, ReplyTo);
builder.Append (' ');
} else {
builder.Append ("NIL ");
}
if (To.Count > 0) {
EncodeAddressList (builder, To);
builder.Append (' ');
} else {
builder.Append ("NIL ");
}
if (Cc.Count > 0) {
EncodeAddressList (builder, Cc);
builder.Append (' ');
} else {
builder.Append ("NIL ");
}
if (Bcc.Count > 0) {
EncodeAddressList (builder, Bcc);
builder.Append (' ');
} else {
builder.Append ("NIL ");
}
if (InReplyTo != null) {
if (InReplyTo.Length > 1 && InReplyTo[0] != '<' && InReplyTo[InReplyTo.Length - 1] != '>')
builder.AppendFormat ("{0} ", MimeUtils.Quote ('<' + InReplyTo + '>'));
else
builder.AppendFormat ("{0} ", MimeUtils.Quote (InReplyTo));
} else
builder.Append ("NIL ");
if (MessageId != null) {
if (MessageId.Length > 1 && MessageId[0] != '<' && MessageId[MessageId.Length - 1] != '>')
builder.AppendFormat ("{0}", MimeUtils.Quote ('<' + MessageId + '>'));
else
builder.AppendFormat ("{0}", MimeUtils.Quote (MessageId));
} else
builder.Append ("NIL");
builder.Append (')');
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.Envelope"/>.
/// </summary>
/// <remarks>
/// <para>The returned string can be parsed by <see cref="TryParse(string,out Envelope)"/>.</para>
/// <note type="warning">The syntax of the string returned, while similar to IMAP's ENVELOPE syntax,
/// is not completely compatible.</note>
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.Envelope"/>.</returns>
public override string ToString ()
{
var builder = new StringBuilder ();
Encode (builder);
return builder.ToString ();
}
static bool TryParse (string text, ref int index, out string nstring)
{
nstring = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (text[index] != '"') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
index += 3;
return true;
}
return false;
}
var token = new StringBuilder ();
bool escaped = false;
index++;
while (index < text.Length) {
if (text[index] == '"' && !escaped)
break;
if (escaped || text[index] != '\\') {
token.Append (text[index]);
escaped = false;
} else {
escaped = true;
}
index++;
}
if (index >= text.Length)
return false;
nstring = token.ToString ();
index++;
return true;
}
static bool TryParse (string text, ref int index, out InternetAddress addr)
{
string name, route, user, domain;
DomainList domains;
addr = null;
if (text[index] != '(')
return false;
index++;
if (!TryParse (text, ref index, out name))
return false;
if (!TryParse (text, ref index, out route))
return false;
if (!TryParse (text, ref index, out user))
return false;
if (!TryParse (text, ref index, out domain))
return false;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length || text[index] != ')')
return false;
index++;
if (domain != null) {
var address = user + "@" + domain;
if (route != null && DomainList.TryParse (route, out domains))
addr = new MailboxAddress (name, domains, address);
else
addr = new MailboxAddress (name, address);
} else if (user != null) {
addr = new GroupAddress (user);
}
return true;
}
static bool TryParse (string text, ref int index, out InternetAddressList list)
{
list = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length)
return false;
if (text[index] != '(') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
list = new InternetAddressList ();
index += 3;
return true;
}
return false;
}
index++;
if (index >= text.Length)
return false;
list = new InternetAddressList ();
var stack = new List<InternetAddressList> ();
int sp = 0;
stack.Add (list);
do {
if (text[index] == ')')
break;
if (!TryParse (text, ref index, out InternetAddress addr))
return false;
if (addr != null) {
var group = addr as GroupAddress;
stack[sp].Add (addr);
if (group != null) {
stack.Add (group.Members);
sp++;
}
} else if (sp > 0) {
stack.RemoveAt (sp);
sp--;
}
while (index < text.Length && text[index] == ' ')
index++;
} while (index < text.Length);
// Note: technically, we should check that sp == 0 as well, since all groups should
// be popped off the stack, but in the interest of being liberal in what we accept,
// we'll ignore that.
if (index >= text.Length)
return false;
index++;
return true;
}
internal static bool TryParse (string text, ref int index, out Envelope envelope)
{
InternetAddressList from, sender, replyto, to, cc, bcc;
string inreplyto, messageid, subject, nstring;
DateTimeOffset? date = null;
envelope = null;
while (index < text.Length && text[index] == ' ')
index++;
if (index >= text.Length || text[index] != '(') {
if (index + 3 <= text.Length && text.Substring (index, 3) == "NIL") {
index += 3;
return true;
}
return false;
}
index++;
if (!TryParse (text, ref index, out nstring))
return false;
if (nstring != null) {
DateTimeOffset value;
if (!DateUtils.TryParse (nstring, out value))
return false;
date = value;
}
if (!TryParse (text, ref index, out subject))
return false;
if (!TryParse (text, ref index, out from))
return false;
if (!TryParse (text, ref index, out sender))
return false;
if (!TryParse (text, ref index, out replyto))
return false;
if (!TryParse (text, ref index, out to))
return false;
if (!TryParse (text, ref index, out cc))
return false;
if (!TryParse (text, ref index, out bcc))
return false;
if (!TryParse (text, ref index, out inreplyto))
return false;
if (!TryParse (text, ref index, out messageid))
return false;
if (index >= text.Length || text[index] != ')')
return false;
index++;
envelope = new Envelope {
Date = date,
Subject = subject,
From = from,
Sender = sender,
ReplyTo = replyto,
To = to,
Cc = cc,
Bcc = bcc,
InReplyTo = inreplyto != null ? MimeUtils.EnumerateReferences (inreplyto).FirstOrDefault () ?? inreplyto : null,
MessageId = messageid != null ? MimeUtils.EnumerateReferences (messageid).FirstOrDefault () ?? messageid : null
};
return true;
}
/// <summary>
/// Tries to parse the given text into a new <see cref="MailKit.Envelope"/> instance.
/// </summary>
/// <remarks>
/// <para>Parses an Envelope value from the specified text.</para>
/// <note type="warning">This syntax, while similar to IMAP's ENVELOPE syntax, is not
/// completely compatible.</note>
/// </remarks>
/// <returns><c>true</c>, if the envelope was successfully parsed, <c>false</c> otherwise.</returns>
/// <param name="text">The text to parse.</param>
/// <param name="envelope">The parsed envelope.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="text"/> is <c>null</c>.
/// </exception>
public static bool TryParse (string text, out Envelope envelope)
{
if (text == null)
throw new ArgumentNullException (nameof (text));
int index = 0;
return TryParse (text, ref index, out envelope) && index == text.Length;
}
}
}

View File

@ -0,0 +1,53 @@
//
// FolderMode.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.
//
namespace MailKit {
/// <summary>
/// A folder access mode.
/// </summary>
/// <remarks>
/// A folder access mode.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadMessages"/>
/// </example>
public enum FolderAccess {
/// <summary>
/// The folder is not open.
/// </summary>
None,
/// <summary>
/// The folder is read-only.
/// </summary>
ReadOnly,
/// <summary>
/// The folder is read/write.
/// </summary>
ReadWrite
}
}

View File

@ -0,0 +1,135 @@
//
// FolderAttributes.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;
namespace MailKit {
/// <summary>
/// Folder attributes as used by <see cref="IMailFolder.Attributes"/>.
/// </summary>
/// <remarks>
/// Folder attributes as used by <see cref="IMailFolder.Attributes"/>.
/// </remarks>
[Flags]
public enum FolderAttributes {
/// <summary>
/// The folder does not have any attributes.
/// </summary>
None = 0,
/// <summary>
/// It is not possible for any subfolders to exist under the folder.
/// </summary>
NoInferiors = (1 << 0),
/// <summary>
/// It is not possible to select the folder.
/// </summary>
NoSelect = (1 << 1),
/// <summary>
/// The folder has been marked as possibly containing new messages
/// since the folder was last selected.
/// </summary>
Marked = (1 << 2),
/// <summary>
/// The folder does not contain any new messages since the folder
/// was last selected.
/// </summary>
Unmarked = (1 << 3),
/// <summary>
/// The folder does not exist, but is simply a place-holder.
/// </summary>
NonExistent = (1 << 4),
/// <summary>
/// The folder is subscribed.
/// </summary>
Subscribed = (1 << 5),
/// <summary>
/// The folder is remote.
/// </summary>
Remote = (1 << 6),
/// <summary>
/// The folder has subfolders.
/// </summary>
HasChildren = (1 << 7),
/// <summary>
/// The folder does not have any subfolders.
/// </summary>
HasNoChildren = (1 << 8),
/// <summary>
/// The folder is a special "All" folder containing an aggregate of all messages.
/// </summary>
All = (1 << 9),
/// <summary>
/// The folder is a special "Archive" folder.
/// </summary>
Archive = (1 << 10),
/// <summary>
/// The folder is the special "Drafts" folder.
/// </summary>
Drafts = (1 << 11),
/// <summary>
/// The folder is the special "Flagged" folder.
/// </summary>
Flagged = (1 << 12),
/// <summary>
/// The folder is the special "Important" folder.
/// </summary>
Important = (1 << 13),
/// <summary>
/// The folder is the special "Inbox" folder.
/// </summary>
Inbox = (1 << 14),
/// <summary>
/// The folder is the special "Junk" folder.
/// </summary>
Junk = (1 << 15),
/// <summary>
/// The folder is the special "Sent" folder.
/// </summary>
Sent = (1 << 16),
/// <summary>
/// The folder is the special "Trash" folder.
/// </summary>
Trash = (1 << 17),
}
}

View File

@ -0,0 +1,67 @@
//
// FolderCreatedEventArgs.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;
namespace MailKit {
/// <summary>
/// Event args used when a <see cref="IMailFolder"/> is created.
/// </summary>
/// <remarks>
/// Event args used when a <see cref="IMailFolder"/> is created.
/// </remarks>
public class FolderCreatedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.FolderCreatedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderCreatedEventArgs"/>.
/// </remarks>
/// <param name="folder">The newly created folder.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folder"/> is <c>null</c>.
/// </exception>
public FolderCreatedEventArgs (IMailFolder folder)
{
if (folder == null)
throw new ArgumentNullException (nameof (folder));
Folder = folder;
}
/// <summary>
/// Get the folder that was just created.
/// </summary>
/// <remarks>
/// Gets the folder that was just created.
/// </remarks>
/// <value>The folder.</value>
public IMailFolder Folder {
get; private set;
}
}
}

View File

@ -0,0 +1,82 @@
//
// FolderFeature.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.
//
namespace MailKit
{
/// <summary>
/// An optional feature that an <see cref="IMailFolder"/> may support.
/// </summary>
/// <remarks>
/// An optional feature that an <see cref="IMailFolder"/> may support.
/// </remarks>
public enum FolderFeature
{
/// <summary>
/// Indicates that the folder supports access rights.
/// </summary>
AccessRights,
/// <summary>
/// Indicates that the folder allows arbitrary annotations to be set on a message.
/// </summary>
Annotations,
/// <summary>
/// Indicates that the folder allows arbitrary metadata to be set.
/// </summary>
Metadata,
/// <summary>
/// Indicates that the folder uses modification sequences for every state change of a message.
/// </summary>
ModSequences,
/// <summary>
/// Indicates that the folder supports quick resynchronization when opening.
/// </summary>
QuickResync,
/// <summary>
/// Indicates that the folder supports quotas.
/// </summary>
Quotas,
/// <summary>
/// Indicates that the folder supports sorting messages.
/// </summary>
Sorting,
/// <summary>
/// Indicates that the folder supports threading messages.
/// </summary>
Threading,
/// <summary>
/// Indicates that the folder supports the use of UTF-8.
/// </summary>
UTF8,
}
}

View File

@ -0,0 +1,74 @@
//
// FolderNamespace.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;
namespace MailKit {
/// <summary>
/// A folder namespace.
/// </summary>
/// <remarks>
/// A folder namespace.
/// </remarks>
public class FolderNamespace
{
/// <summary>
/// The directory separator for this folder namespace.
/// </summary>
/// <remarks>
/// The directory separator for this folder namespace.
/// </remarks>
public readonly char DirectorySeparator;
/// <summary>
/// The base path for this folder namespace.
/// </summary>
/// <remarks>
/// The base path for this folder namespace.
/// </remarks>
public readonly string Path;
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.FolderNamespace"/> class.
/// </summary>
/// <remarks>
/// Creates a new folder namespace.
/// </remarks>
/// <param name="directorySeparator">The directory separator.</param>
/// <param name="path">The folder path.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> is <c>null</c>.
/// </exception>
public FolderNamespace (char directorySeparator, string path)
{
if (path == null)
throw new ArgumentNullException (nameof (path));
DirectorySeparator = directorySeparator;
Path = path;
}
}
}

View File

@ -0,0 +1,235 @@
//
// FolderNamespaceCollection.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.Text;
using System.Collections;
using System.Collections.Generic;
using MimeKit.Utils;
namespace MailKit {
/// <summary>
/// A read-only collection of folder namespaces.
/// </summary>
/// <remarks>
/// A read-only collection of folder namespaces.
/// </remarks>
public class FolderNamespaceCollection : IEnumerable<FolderNamespace>
{
readonly List<FolderNamespace> namespaces;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNamespaceCollection"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNamespaceCollection"/>.
/// </remarks>
public FolderNamespaceCollection ()
{
namespaces = new List<FolderNamespace> ();
}
#region ICollection implementation
/// <summary>
/// Gets the number of folder namespaces contained in the collection.
/// </summary>
/// <remarks>
/// Gets the number of folder namespaces contained in the collection.
/// </remarks>
/// <value>The count.</value>
public int Count {
get { return namespaces.Count; }
}
/// <summary>
/// Adds the specified namespace.
/// </summary>
/// <remarks>
/// Adds the specified namespace.
/// </remarks>
/// <param name="namespace">The namespace to add.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
public void Add (FolderNamespace @namespace)
{
if (@namespace == null)
throw new ArgumentNullException (nameof (@namespace));
namespaces.Add (@namespace);
}
/// <summary>
/// Removes all namespaces from the collection.
/// </summary>
/// <remarks>
/// Removes all namespaces from the collection.
/// </remarks>
public void Clear ()
{
namespaces.Clear ();
}
/// <summary>
/// Checks if the collection contains the specified namespace.
/// </summary>
/// <remarks>
/// Checks if the collection contains the specified namespace.
/// </remarks>
/// <returns><value>true</value> if the specified namespace exists;
/// otherwise <value>false</value>.</returns>
/// <param name="namespace">The namespace.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
public bool Contains (FolderNamespace @namespace)
{
if (@namespace == null)
throw new ArgumentNullException (nameof (@namespace));
return namespaces.Contains (@namespace);
}
/// <summary>
/// Removes the first occurance of the specified namespace.
/// </summary>
/// <remarks>
/// Removes the first occurance of the specified namespace.
/// </remarks>
/// <returns><value>true</value> if the frst occurance of the specified
/// namespace was removed; otherwise <value>false</value>.</returns>
/// <param name="namespace">The namespace.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
public bool Remove (FolderNamespace @namespace)
{
if (@namespace == null)
throw new ArgumentNullException (nameof (@namespace));
return namespaces.Remove (@namespace);
}
/// <summary>
/// Gets the <see cref="MailKit.FolderNamespace"/> at the specified index.
/// </summary>
/// <remarks>
/// Gets the <see cref="MailKit.FolderNamespace"/> at the specified index.
/// </remarks>
/// <value>The folder namespace at the specified index.</value>
/// <param name="index">The index.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="value"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public FolderNamespace this [int index] {
get {
if (index < 0 || index >= namespaces.Count)
throw new ArgumentOutOfRangeException (nameof (index));
return namespaces[index];
}
set {
if (index < 0 || index >= namespaces.Count)
throw new ArgumentOutOfRangeException (nameof (index));
if (value == null)
throw new ArgumentNullException (nameof (value));
namespaces[index] = value;
}
}
#endregion
#region IEnumerable implementation
/// <summary>
/// Gets the enumerator.
/// </summary>
/// <remarks>
/// Gets the enumerator.
/// </remarks>
/// <returns>The enumerator.</returns>
public IEnumerator<FolderNamespace> GetEnumerator ()
{
return namespaces.GetEnumerator ();
}
#endregion
#region IEnumerable implementation
/// <summary>
/// Gets the enumerator.
/// </summary>
/// <remarks>
/// Gets the enumerator.
/// </remarks>
/// <returns>The enumerator.</returns>
IEnumerator IEnumerable.GetEnumerator ()
{
return namespaces.GetEnumerator ();
}
#endregion
static bool Escape (char directorySeparator)
{
return directorySeparator == '\\' || directorySeparator == '"';
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:MailKit.FolderNamespaceCollection"/>.
/// </summary>
/// <remarks>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:MailKit.FolderNamespaceCollection"/>.
/// </remarks>
/// <returns>A <see cref="T:System.String"/> that represents the current <see cref="T:MailKit.FolderNamespaceCollection"/>.</returns>
public override string ToString ()
{
var builder = new StringBuilder ();
builder.Append ('(');
for (int i = 0; i < namespaces.Count; i++) {
builder.Append ("(\"");
if (Escape (namespaces[i].DirectorySeparator))
builder.Append ('\\');
builder.Append (namespaces[i].DirectorySeparator);
builder.Append ("\" ");
builder.Append (MimeUtils.Quote (namespaces[i].Path));
builder.Append (")");
}
builder.Append (')');
return builder.ToString ();
}
}
}

View File

@ -0,0 +1,149 @@
//
// FolderNotFoundException.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;
#if SERIALIZABLE
using System.Security;
using System.Runtime.Serialization;
#endif
namespace MailKit {
/// <summary>
/// The exception that is thrown when a folder could not be found.
/// </summary>
/// <remarks>
/// This exception is thrown by <see cref="IMailFolder.GetSubfolder(string,System.Threading.CancellationToken)"/>.
/// </remarks>
#if SERIALIZABLE
[Serializable]
#endif
public class FolderNotFoundException : Exception
{
#if SERIALIZABLE
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Deserializes a <see cref="FolderNotFoundException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
protected FolderNotFoundException (SerializationInfo info, StreamingContext context) : base (info, context)
{
FolderName = info.GetString ("FolderName");
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNotFoundException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
/// <param name="folderName">The name of the folder.</param>
/// <param name="innerException">The inner exception.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folderName"/> is <c>null</c>.
/// </exception>
public FolderNotFoundException (string message, string folderName, Exception innerException) : base (message, innerException)
{
if (folderName == null)
throw new ArgumentNullException (nameof (folderName));
FolderName = folderName;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNotFoundException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
/// <param name="folderName">The name of the folder.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folderName"/> is <c>null</c>.
/// </exception>
public FolderNotFoundException (string message, string folderName) : base (message)
{
if (folderName == null)
throw new ArgumentNullException (nameof (folderName));
FolderName = folderName;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNotFoundException"/>.
/// </remarks>
/// <param name="folderName">The name of the folder.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folderName"/> is <c>null</c>.
/// </exception>
public FolderNotFoundException (string folderName) : this ("The requested folder could not be found.", folderName)
{
}
/// <summary>
/// Gets the name of the folder that could not be found.
/// </summary>
/// <remarks>
/// Gets the name of the folder that could not be found.
/// </remarks>
/// <value>The name of the folder.</value>
public string FolderName {
get; private set;
}
#if SERIALIZABLE
/// <summary>
/// When overridden in a derived class, sets the <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// with information about the exception.
/// </summary>
/// <remarks>
/// Serializes the state of the <see cref="FolderNotFoundException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
[SecurityCritical]
public override void GetObjectData (SerializationInfo info, StreamingContext context)
{
base.GetObjectData (info, context);
info.AddValue ("FolderName", FolderName);
}
#endif
}
}

View File

@ -0,0 +1,184 @@
//
// FolderNotOpenException.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;
#if SERIALIZABLE
using System.Runtime.Serialization;
#endif
namespace MailKit {
/// <summary>
/// The exception that is thrown when a folder is not open.
/// </summary>
/// <remarks>
/// This exception is thrown when an operation on a folder could not be completed
/// due to the folder being in a closed state. For example, the
/// <see cref="IMailFolder.GetMessage(UniqueId,System.Threading.CancellationToken, ITransferProgress)"/>
/// method will throw a <see cref="FolderNotOpenException"/> if the folder is not
/// current open.
/// </remarks>
#if SERIALIZABLE
[Serializable]
#endif
public class FolderNotOpenException : InvalidOperationException
{
#if SERIALIZABLE
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotOpenException"/> class.
/// </summary>
/// <remarks>
/// Deserializes a <see cref="FolderNotOpenException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
protected FolderNotOpenException (SerializationInfo info, StreamingContext context) : base (info, context)
{
var value = info.GetString ("FolderAccess");
FolderAccess access;
if (!Enum.TryParse (value, out access))
FolderAccess = FolderAccess.ReadOnly;
else
FolderAccess = access;
FolderName = info.GetString ("FolderName");
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotOpenException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNotOpenException"/>.
/// </remarks>
/// <param name="folderName">The folder name.</param>
/// <param name="access">The minimum folder access required by the operation.</param>
/// <param name="message">The error message.</param>
/// <param name="innerException">The inner exception.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folderName"/> is <c>null</c>.
/// </exception>
public FolderNotOpenException (string folderName, FolderAccess access, string message, Exception innerException) : base (message, innerException)
{
if (folderName == null)
throw new ArgumentNullException (nameof (folderName));
FolderName = folderName;
FolderAccess = access;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotOpenException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNotOpenException"/>.
/// </remarks>
/// <param name="folderName">The folder name.</param>
/// <param name="access">The minimum folder access required by the operation.</param>
/// <param name="message">The error message.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folderName"/> is <c>null</c>.
/// </exception>
public FolderNotOpenException (string folderName, FolderAccess access, string message) : base (message)
{
if (folderName == null)
throw new ArgumentNullException (nameof (folderName));
FolderName = folderName;
FolderAccess = access;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderNotOpenException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderNotOpenException"/>.
/// </remarks>
/// <param name="folderName">The folder name.</param>
/// <param name="access">The minimum folder access required by the operation.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folderName"/> is <c>null</c>.
/// </exception>
public FolderNotOpenException (string folderName, FolderAccess access) : this (folderName, access, GetDefaultMessage (access))
{
}
/// <summary>
/// Get the name of the folder.
/// </summary>
/// <remarks>
/// Gets the name of the folder.
/// </remarks>
/// <value>The name of the folder.</value>
public string FolderName {
get; private set;
}
/// <summary>
/// Get the minimum folder access required by the operation.
/// </summary>
/// <remarks>
/// Gets the minimum folder access required by the operation.
/// </remarks>
/// <value>The minimum required folder access.</value>
public FolderAccess FolderAccess {
get; private set;
}
static string GetDefaultMessage (FolderAccess access)
{
if (access == FolderAccess.ReadWrite)
return "The folder is not currently open in read-write mode.";
return "The folder is not currently open.";
}
#if SERIALIZABLE
/// <summary>
/// When overridden in a derived class, sets the <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// with information about the exception.
/// </summary>
/// <remarks>
/// Serializes the state of the <see cref="FolderNotOpenException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
public override void GetObjectData (SerializationInfo info, StreamingContext context)
{
base.GetObjectData (info, context);
info.AddValue ("FolderAccess", FolderAccess.ToString ());
info.AddValue ("FolderName", FolderName);
}
#endif
}
}

124
src/MailKit/FolderQuota.cs Normal file
View File

@ -0,0 +1,124 @@
//
// FolderQuota.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;
namespace MailKit {
/// <summary>
/// A folder quota.
/// </summary>
/// <remarks>
/// A <see cref="FolderQuota"/> is returned by <see cref="IMailFolder.GetQuota(System.Threading.CancellationToken)"/>.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
public class FolderQuota
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.FolderQuota"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderQuota"/> with the specified root.
/// </remarks>
/// <param name="quotaRoot">The quota root.</param>
public FolderQuota (IMailFolder quotaRoot)
{
QuotaRoot = quotaRoot;
}
/// <summary>
/// Get the quota root.
/// </summary>
/// <remarks>
/// Gets the quota root. If the quota root is <c>null</c>, then
/// it suggests that the folder does not have a quota.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The quota root.</value>
public IMailFolder QuotaRoot {
get; private set;
}
/// <summary>
/// Get or set the message limit.
/// </summary>
/// <remarks>
/// Gets or sets the message limit.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The message limit.</value>
public uint? MessageLimit {
get; set;
}
/// <summary>
/// Get or set the storage limit, in kilobytes.
/// </summary>
/// <remarks>
/// Gets or sets the storage limit, in kilobytes.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The storage limit, in kilobytes.</value>
public uint? StorageLimit {
get; set;
}
/// <summary>
/// Get or set the current message count.
/// </summary>
/// <remarks>
/// Gets or sets the current message count.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The current message count.</value>
public uint? CurrentMessageCount {
get; set;
}
/// <summary>
/// Gets or sets the size of the current storage, in kilobytes.
/// </summary>
/// <remarks>
/// Gets or sets the size of the current storage, in kilobytes.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The size of the current storage, in kilobytes.</value>
public uint? CurrentStorageSize {
get; set;
}
}
}

View File

@ -0,0 +1,85 @@
//
// FolderRenamedEventArgs.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;
namespace MailKit {
/// <summary>
/// Event args used when a <see cref="IMailFolder"/> is renamed.
/// </summary>
/// <remarks>
/// Event args used when a <see cref="IMailFolder"/> is renamed.
/// </remarks>
public class FolderRenamedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.FolderRenamedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="FolderRenamedEventArgs"/>.
/// </remarks>
/// <param name="oldName">The old name of the folder.</param>
/// <param name="newName">The new name of the folder.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="oldName"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="newName"/> is <c>null</c>.</para>
/// </exception>
public FolderRenamedEventArgs (string oldName, string newName)
{
if (oldName == null)
throw new ArgumentNullException (nameof (oldName));
if (newName == null)
throw new ArgumentNullException (nameof (newName));
OldName = oldName;
NewName = newName;
}
/// <summary>
/// The old name of the folder.
/// </summary>
/// <remarks>
/// The old name of the folder.
/// </remarks>
/// <value>The old name.</value>
public string OldName {
get; private set;
}
/// <summary>
/// The new name of the folder.
/// </summary>
/// <remarks>
/// The new name of the folder.
/// </remarks>
/// <value>The new name.</value>
public string NewName {
get; private set;
}
}
}

5077
src/MailKit/IMailFolder.cs Normal file

File diff suppressed because it is too large Load Diff

1118
src/MailKit/IMailService.cs Normal file

File diff suppressed because it is too large Load Diff

511
src/MailKit/IMailSpool.cs Normal file
View File

@ -0,0 +1,511 @@
//
// IMailSpool.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.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using MimeKit;
namespace MailKit {
/// <summary>
/// An interface for retreiving messages from a spool.
/// </summary>
/// <remarks>
/// An interface for retreiving messages from a spool.
/// </remarks>
public interface IMailSpool : IMailService, IEnumerable<MimeMessage>
{
/// <summary>
/// Get the number of messages available in the message spool.
/// </summary>
/// <remarks>
/// <para>Gets the number of messages available in the message spool.</para>
/// <para>Once authenticated, the <see cref="Count"/> property will be set
/// to the number of available messages in the spool.</para>
/// </remarks>
/// <value>The message count.</value>
int Count { get; }
/// <summary>
/// Get whether or not the service supports referencing messages by UIDs.
/// </summary>
/// <remarks>
/// <para>Not all servers support referencing messages by UID, so this property should
/// be checked before using <see cref="GetMessageUid(int, CancellationToken)"/>
/// and <see cref="GetMessageUids(CancellationToken)"/>.</para>
/// <para>If the server does not support UIDs, then all methods that take UID arguments
/// along with <see cref="GetMessageUid(int, CancellationToken)"/> and
/// <see cref="GetMessageUids(CancellationToken)"/> will fail.</para>
/// </remarks>
/// <value><c>true</c> if supports uids; otherwise, <c>false</c>.</value>
bool SupportsUids { get; }
/// <summary>
/// Get the message count.
/// </summary>
/// <remarks>
/// Gets the message count.
/// </remarks>
/// <returns>The message count.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
int GetMessageCount (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the UID of the message at the specified index.
/// </summary>
/// <remarks>
/// Not all servers support UIDs, so you should first check
/// the <see cref="SupportsUids"/> property.
/// </remarks>
/// <returns>The message UID.</returns>
/// <param name="index">The message index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
string GetMessageUid (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the UID of the message at the specified index.
/// </summary>
/// <remarks>
/// Not all servers support UIDs, so you should first check
/// the <see cref="SupportsUids"/> property.
/// </remarks>
/// <returns>The message UID.</returns>
/// <param name="index">The message index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<string> GetMessageUidAsync (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the full list of available message UIDs.
/// </summary>
/// <remarks>
/// Not all servers support UIDs, so you should first check
/// the <see cref="SupportsUids"/> property.
/// </remarks>
/// <returns>The message UIDs.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
IList<string> GetMessageUids (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the full list of available message UIDs.
/// </summary>
/// <remarks>
/// Not all servers support UIDs, so you should first check
/// the <see cref="SupportsUids"/> property.
/// </remarks>
/// <returns>The message UIDs.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Task<IList<string>> GetMessageUidsAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the size of the specified message, in bytes.
/// </summary>
/// <remarks>
/// Gets the size of the specified message, in bytes.
/// </remarks>
/// <returns>The message size, in bytes.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
int GetMessageSize (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the size of the specified message, in bytes.
/// </summary>
/// <remarks>
/// Asynchronously gets the size of the specified message, in bytes.
/// </remarks>
/// <returns>The message size, in bytes.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<int> GetMessageSizeAsync (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the sizes for all available messages, in bytes.
/// </summary>
/// <remarks>
/// Gets the sizes for all available messages, in bytes.
/// </remarks>
/// <returns>The message sizes, in bytes.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
IList<int> GetMessageSizes (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the sizes for all available messages, in bytes.
/// </summary>
/// <remarks>
/// Asynchronously gets the sizes for all available messages, in bytes.
/// </remarks>
/// <returns>The message sizes, in bytes.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Task<IList<int>> GetMessageSizesAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the headers for the specified message.
/// </summary>
/// <remarks>
/// Gets the headers for the specified message.
/// </remarks>
/// <returns>The message headers.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
HeaderList GetMessageHeaders (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the headers for the specified message.
/// </summary>
/// <remarks>
/// Asynchronously gets the headers for the specified message.
/// </remarks>
/// <returns>The message headers.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<HeaderList> GetMessageHeadersAsync (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the headers for the specified messages.
/// </summary>
/// <remarks>
/// Gets the headers for the specified messages.
/// </remarks>
/// <returns>The headers for the specified messages.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
IList<HeaderList> GetMessageHeaders (IList<int> indexes, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the headers for the specified messages.
/// </summary>
/// <remarks>
/// Asynchronously gets the headers for the specified messages.
/// </remarks>
/// <returns>The headers for the specified messages.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<IList<HeaderList>> GetMessageHeadersAsync (IList<int> indexes, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the headers of the messages within the specified range.
/// </summary>
/// <remarks>
/// Gets the headers of the messages within the specified range.
/// </remarks>
/// <returns>The headers of the messages within the specified range.</returns>
/// <param name="startIndex">The index of the first message to get.</param>
/// <param name="count">The number of messages to get.</param>
/// <param name="cancellationToken">The cancellation token.</param>
IList<HeaderList> GetMessageHeaders (int startIndex, int count, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the headers of the messages within the specified range.
/// </summary>
/// <remarks>
/// Gets the headers of the messages within the specified range.
/// </remarks>
/// <returns>The headers of the messages within the specified range.</returns>
/// <param name="startIndex">The index of the first message to get.</param>
/// <param name="count">The number of messages to get.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<IList<HeaderList>> GetMessageHeadersAsync (int startIndex, int count, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the message at the specified index.
/// </summary>
/// <remarks>
/// Gets the message at the specified index.
/// </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>
MimeMessage GetMessage (int index, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously get the message at the specified index.
/// </summary>
/// <remarks>
/// Asynchronously gets the message at the specified index.
/// </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>
Task<MimeMessage> GetMessageAsync (int index, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Get the messages at the specified indexes.
/// </summary>
/// <remarks>
/// Gets the messages at the specified indexes.
/// </remarks>
/// <returns>The messages.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
IList<MimeMessage> GetMessages (IList<int> indexes, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously get the messages at the specified indexes.
/// </summary>
/// <remarks>
/// Asynchronously gets the messages at the specified indexes.
/// </remarks>
/// <returns>The messages.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task<IList<MimeMessage>> GetMessagesAsync (IList<int> indexes, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Get the messages within the specified range.
/// </summary>
/// <remarks>
/// Gets the messages within the specified range.
/// </remarks>
/// <returns>The messages.</returns>
/// <param name="startIndex">The index of the first message to get.</param>
/// <param name="count">The number of messages to get.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
IList<MimeMessage> GetMessages (int startIndex, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously get the messages within the specified range.
/// </summary>
/// <remarks>
/// Asynchronously gets the messages within the specified range.
/// </remarks>
/// <returns>The messages.</returns>
/// <param name="startIndex">The index of the first message to get.</param>
/// <param name="count">The number of messages to get.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task<IList<MimeMessage>> GetMessagesAsync (int startIndex, int count, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Get the message or header stream at the specified index.
/// </summary>
/// <remarks>
/// Gets the message or header stream at the specified index.
/// </remarks>
/// <returns>The message or header stream.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="headersOnly"><c>true</c> if only the headers should be retrieved; otherwise, <c>false</c>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Stream GetStream (int index, bool headersOnly = false, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously get the message or header stream at the specified index.
/// </summary>
/// <remarks>
/// Asynchronously gets the message or header stream at the specified index.
/// </remarks>
/// <returns>The message or header stream.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="headersOnly"><c>true</c> if only the headers should be retrieved; otherwise, <c>false</c>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task<Stream> GetStreamAsync (int index, bool headersOnly = false, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Get the message or header streams at the specified index.
/// </summary>
/// <remarks>
/// Gets the message or header streams at the specified index.
/// </remarks>
/// <returns>The message or header streams.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="headersOnly"><c>true</c> if only the headers should be retrieved; otherwise, <c>false</c>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
IList<Stream> GetStreams (IList<int> indexes, bool headersOnly = false, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously get the message or header streams at the specified indexes.
/// </summary>
/// <remarks>
/// Asynchronously gets the message or header streams at the specified indexes.
/// </remarks>
/// <returns>The message or header streams.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="headersOnly"><c>true</c> if only the headers should be retrieved; otherwise, <c>false</c>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task<IList<Stream>> GetStreamsAsync (IList<int> indexes, bool headersOnly = false, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Get the message or header streams within the specified range.
/// </summary>
/// <remarks>
/// Gets the message or header streams within the specified range.
/// </remarks>
/// <returns>The message or header streams.</returns>
/// <param name="startIndex">The index of the first stream to get.</param>
/// <param name="count">The number of streams to get.</param>
/// <param name="headersOnly"><c>true</c> if only the headers should be retrieved; otherwise, <c>false</c>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
IList<Stream> GetStreams (int startIndex, int count, bool headersOnly = false, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously get the message or header streams within the specified range.
/// </summary>
/// <remarks>
/// Asynchronously gets the message or header streams within the specified range.
/// </remarks>
/// <returns>The messages.</returns>
/// <param name="startIndex">The index of the first stream to get.</param>
/// <param name="count">The number of streams to get.</param>
/// <param name="headersOnly"><c>true</c> if only the headers should be retrieved; otherwise, <c>false</c>.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task<IList<Stream>> GetStreamsAsync (int startIndex, int count, bool headersOnly = false, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Mark the specified message for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <param name="index">The index of the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
void DeleteMessage (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously mark the specified message for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="index">The index of the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task DeleteMessageAsync (int index, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Mark the specified messages for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
void DeleteMessages (IList<int> indexes, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously mark the specified messages for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task DeleteMessagesAsync (IList<int> indexes, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Mark the specified range of messages for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <param name="startIndex">The index of the first message to mark for deletion.</param>
/// <param name="count">The number of messages to mark for deletion.</param>
/// <param name="cancellationToken">The cancellation token.</param>
void DeleteMessages (int startIndex, int count, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously mark the specified range of messages for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="startIndex">The index of the first message to mark for deletion.</param>
/// <param name="count">The number of messages to mark for deletion.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task DeleteMessagesAsync (int startIndex, int count, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Mark all messages for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
void DeleteAllMessages (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously mark all messages for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Task DeleteAllMessagesAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Reset the state of all messages marked for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
void Reset (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously reset the state of all messages marked for deletion.
/// </summary>
/// <remarks>
/// Messages marked for deletion are not actually deleted until the session
/// is cleanly disconnected
/// (see <see cref="IMailService.Disconnect(bool, CancellationToken)"/>).
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
Task ResetAsync (CancellationToken cancellationToken = default (CancellationToken));
}
}

549
src/MailKit/IMailStore.cs Normal file
View File

@ -0,0 +1,549 @@
//
// IMailStore.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace MailKit {
/// <summary>
/// An interface for retreiving messages from a message store such as IMAP.
/// </summary>
/// <remarks>
/// Implemented by <see cref="MailKit.Net.Imap.ImapClient"/>.
/// </remarks>
public interface IMailStore : IMailService
{
/// <summary>
/// Get the personal namespaces.
/// </summary>
/// <remarks>
/// The personal folder namespaces contain a user's personal mailbox folders.
/// </remarks>
/// <value>The personal namespaces.</value>
FolderNamespaceCollection PersonalNamespaces { get; }
/// <summary>
/// Get the shared namespaces.
/// </summary>
/// <remarks>
/// The shared folder namespaces contain mailbox folders that are shared with the user.
/// </remarks>
/// <value>The shared namespaces.</value>
FolderNamespaceCollection SharedNamespaces { get; }
/// <summary>
/// Get the other namespaces.
/// </summary>
/// <remarks>
/// The other folder namespaces contain other mailbox folders.
/// </remarks>
/// <value>The other namespaces.</value>
FolderNamespaceCollection OtherNamespaces { get; }
/// <summary>
/// Get whether or not the mail store supports quotas.
/// </summary>
/// <remarks>
/// Gets whether or not the mail store supports quotas.
/// </remarks>
/// <value><c>true</c> if the mail store supports quotas; otherwise, <c>false</c>.</value>
bool SupportsQuotas { get; }
/// <summary>
/// Get the threading algorithms supported by the mail store.
/// </summary>
/// <remarks>
/// The threading algorithms are queried as part of the
/// <a href="Overload_MailKit_IMailStore_Connect.htm">Connect</a>
/// and <a href="Overload_MailKit_IMailStore_Authenticate.htm">Authenticate</a> methods.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The threading algorithms.</value>
HashSet<ThreadingAlgorithm> ThreadingAlgorithms { get; }
/// <summary>
/// Get the Inbox folder.
/// </summary>
/// <remarks>
/// The Inbox folder is the default folder and is typically the folder
/// where all new messages are delivered.
/// </remarks>
/// <value>The Inbox folder.</value>
IMailFolder Inbox { get; }
/// <summary>
/// Enable the quick resynchronization feature.
/// </summary>
/// <remarks>
/// <para>Enables quick resynchronization when a folder is opened using the
/// <see cref="IMailFolder.Open(FolderAccess,uint,ulong,System.Collections.Generic.IList&lt;UniqueId&gt;,System.Threading.CancellationToken)"/>
/// method.</para>
/// <para>If this feature is enabled, the <see cref="IMailFolder.MessageExpunged"/> event
/// is replaced with the <see cref="IMailFolder.MessagesVanished"/> event.</para>
/// <para>This method needs to be called immediately after
/// <see cref="IMailService.Authenticate(System.Net.ICredentials,System.Threading.CancellationToken)"/>,
/// before the opening of any folders.</para>
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailService"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailService"/> is not authenticated.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Quick resynchronization needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The mail store does not support quick resynchronization.
/// </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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
void EnableQuickResync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously enable the quick resynchronization feature.
/// </summary>
/// <remarks>
/// <para>Enables quick resynchronization when a folder is opened using the
/// <see cref="IMailFolder.Open(FolderAccess,uint,ulong,System.Collections.Generic.IList&lt;UniqueId&gt;,System.Threading.CancellationToken)"/>
/// method.</para>
/// <para>If this feature is enabled, the <see cref="IMailFolder.MessageExpunged"/> event
/// is replaced with the <see cref="IMailFolder.MessagesVanished"/> event.</para>
/// <para>This method needs to be called immediately after
/// <see cref="IMailService.Authenticate(System.Net.ICredentials,System.Threading.CancellationToken)"/>,
/// before the opening of any folders.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailService"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailService"/> is not authenticated.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Quick resynchronization needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The mail store does not support quick resynchronization.
/// </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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
Task EnableQuickResyncAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the specified special folder.
/// </summary>
/// <remarks>
/// Not all message stores support the concept of special folders,
/// so this method may return <c>null</c>.
/// </remarks>
/// <returns>The folder if available; otherwise <c>null</c>.</returns>
/// <param name="folder">The type of special folder.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="folder"/> is out of range.
/// </exception>
IMailFolder GetFolder (SpecialFolder folder);
/// <summary>
/// Get the folder for the specified namespace.
/// </summary>
/// <remarks>
/// The main reason to get the toplevel folder in a namespace is
/// to list its child folders.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="namespace">The namespace.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
IMailFolder GetFolder (FolderNamespace @namespace);
/// <summary>
/// Get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailService"/> has been disposed.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailService"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailService"/> is not authenticated.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The namespace folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
IList<IMailFolder> GetFolders (FolderNamespace @namespace, bool subscribedOnly, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Asynchronously gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailService"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailService"/> is not authenticated.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The namespace folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
Task<IList<IMailFolder>> GetFoldersAsync (FolderNamespace @namespace, bool subscribedOnly, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="items">The status items to pre-populate.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailService"/> has been disposed.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailService"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailService"/> is not authenticated.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The namespace folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
IList<IMailFolder> GetFolders (FolderNamespace @namespace, StatusItems items = StatusItems.None, bool subscribedOnly = false, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Asynchronously gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="items">The status items to pre-populate.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailService"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailService"/> is not authenticated.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The namespace folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
Task<IList<IMailFolder>> GetFoldersAsync (FolderNamespace @namespace, StatusItems items = StatusItems.None, bool subscribedOnly = false, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the folder for the specified path.
/// </summary>
/// <remarks>
/// Gets the folder for the specified path.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="path">The folder path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
IMailFolder GetFolder (string path, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the folder for the specified path.
/// </summary>
/// <remarks>
/// Asynchronously gets the folder for the specified path.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="path">The folder path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
Task<IMailFolder> GetFolderAsync (string path, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata value.</returns>
/// <param name="tag">The metadata tag.</param>
/// <param name="cancellationToken">The cancellation token.</param>
string GetMetadata (MetadataTag tag, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata value.</returns>
/// <param name="tag">The metadata tag.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<string> GetMetadataAsync (MetadataTag tag, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
MetadataCollection GetMetadata (IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<MetadataCollection> GetMetadataAsync (IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="options">The metadata options.</param>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
MetadataCollection GetMetadata (MetadataOptions options, IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="options">The metadata options.</param>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task<MetadataCollection> GetMetadataAsync (MetadataOptions options, IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Sets the specified metadata.
/// </summary>
/// <remarks>
/// Sets the specified metadata.
/// </remarks>
/// <param name="metadata">The metadata.</param>
/// <param name="cancellationToken">The cancellation token.</param>
void SetMetadata (MetadataCollection metadata, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously sets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously sets the specified metadata.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="metadata">The metadata.</param>
/// <param name="cancellationToken">The cancellation token.</param>
Task SetMetadataAsync (MetadataCollection metadata, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Occurs when a remote message store receives an alert message from the server.
/// </summary>
/// <remarks>
/// Some implementations, such as <see cref="MailKit.Net.Imap.ImapClient"/>,
/// will emit Alert events when they receive alert messages from the server.
/// </remarks>
event EventHandler<AlertEventArgs> Alert;
/// <summary>
/// Occurs when a folder is created.
/// </summary>
/// <remarks>
/// The <see cref="FolderCreated"/> event is emitted when a new folder is created.
/// </remarks>
event EventHandler<FolderCreatedEventArgs> FolderCreated;
/// <summary>
/// Occurs when metadata changes.
/// </summary>
/// <remarks>
/// The <see cref="MetadataChanged"/> event is emitted when metadata changes.
/// </remarks>
event EventHandler<MetadataChangedEventArgs> MetadataChanged;
}
}

View File

@ -0,0 +1,179 @@
//
// IMailTransport.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using MimeKit;
namespace MailKit {
/// <summary>
/// An interface for sending messages.
/// </summary>
/// <remarks>
/// An interface for sending messages.
/// </remarks>
public interface IMailTransport : IMailService
{
/// <summary>
/// Send the specified message.
/// </summary>
/// <remarks>
/// <para>Sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
void Send (MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously send the specified message.
/// </summary>
/// <remarks>
/// <para>Asynchronously sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task SendAsync (MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
void Send (MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Asynchronously sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task SendAsync (MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Send the specified message.
/// </summary>
/// <remarks>
/// <para>Sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
void Send (FormatOptions options, MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously send the specified message.
/// </summary>
/// <remarks>
/// <para>Asynchronously sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task SendAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
void Send (FormatOptions options, MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Asynchronously sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
Task SendAsync (FormatOptions options, MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Occurs when a message is successfully sent via the transport.
/// </summary>
/// <remarks>
/// The <see cref="MessageSent"/> event will be emitted each time a message is successfully sent.
/// </remarks>
event EventHandler<MessageSentEventArgs> MessageSent;
}
}

View File

@ -0,0 +1,460 @@
//
// IMessageSummary.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.Collections.Generic;
using MimeKit;
namespace MailKit {
/// <summary>
/// A summary of a message.
/// </summary>
/// <remarks>
/// <para>The <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a> and
/// <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a> methods
/// return lists of <see cref="IMessageSummary"/> items.</para>
/// <para>The properties of the <see cref="IMessageSummary"/> that will be available
/// depend on the <see cref="MessageSummaryItems"/> passed to the aformentioned method.</para>
/// </remarks>
public interface IMessageSummary
{
/// <summary>
/// Get the folder that the message belongs to.
/// </summary>
/// <remarks>
/// Gets the folder that the message belongs to, if available.
/// </remarks>
/// <value>The folder.</value>
IMailFolder Folder {
get;
}
/// <summary>
/// Get a bitmask of fields that have been populated.
/// </summary>
/// <remarks>
/// Gets a bitmask of fields that have been populated.
/// </remarks>
/// <value>The fields that have been populated.</value>
MessageSummaryItems Fields { get; }
/// <summary>
/// Gets the body structure of the message, if available.
/// </summary>
/// <remarks>
/// <para>The body will be one of <see cref="BodyPartText"/>,
/// <see cref="BodyPartMessage"/>, <see cref="BodyPartBasic"/>,
/// or <see cref="BodyPartMultipart"/>.</para>
/// <para>This property will only be set if either the
/// <see cref="MessageSummaryItems.Body"/> flag or the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The body structure of the message.</value>
BodyPart Body { get; }
/// <summary>
/// Gets the text body part of the message if it exists.
/// </summary>
/// <remarks>
/// <para>Gets the <c>text/plain</c> body part of the message.</para>
/// <para>This property will only be usable if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
/// <value>The text body if it exists; otherwise, <c>null</c>.</value>
BodyPartText TextBody { get; }
/// <summary>
/// Gets the html body part of the message if it exists.
/// </summary>
/// <remarks>
/// <para>Gets the <c>text/html</c> body part of the message.</para>
/// <para>This property will only be usable if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The html body if it exists; otherwise, <c>null</c>.</value>
BodyPartText HtmlBody { get; }
/// <summary>
/// Gets the body parts of the message.
/// </summary>
/// <remarks>
/// <para>Traverses over the <see cref="Body"/>, enumerating all of the
/// <see cref="BodyPartBasic"/> objects.</para>
/// <para>This property will only be usable if either the
/// <see cref="MessageSummaryItems.Body"/> flag or the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The body parts.</value>
IEnumerable<BodyPartBasic> BodyParts { get; }
/// <summary>
/// Gets the attachments.
/// </summary>
/// <remarks>
/// <para>Traverses over the <see cref="Body"/>, enumerating all of the
/// <see cref="BodyPartBasic"/> objects that have a <c>Content-Disposition</c>
/// header set to <c>"attachment"</c>.</para>
/// <para>This property will only be usable if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
/// <value>The attachments.</value>
IEnumerable<BodyPartBasic> Attachments { get; }
/// <summary>
/// Gets the preview text of the message.
/// </summary>
/// <remarks>
/// <para>The preview text is a short snippet of the beginning of the message
/// text, typically shown in a mail client's message list to provide the user
/// with a sense of what the message is about.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.PreviewText"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The preview text.</value>
string PreviewText { get; }
/// <summary>
/// Gets the envelope of the message, if available.
/// </summary>
/// <remarks>
/// <para>The envelope of a message contains information such as the
/// date the message was sent, the subject of the message,
/// the sender of the message, who the message was sent to,
/// which message(s) the message may be in reply to,
/// and the message id.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Envelope"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The envelope of the message.</value>
Envelope Envelope { get; }
/// <summary>
/// Gets the normalized subject.
/// </summary>
/// <remarks>
/// <para>A normalized <c>Subject</c> header value where prefixes such as <c>"Re:"</c>, <c>"Re[#]:"</c> and <c>"FWD:"</c> have been pruned.</para>
/// <para>This property is typically used for threading messages by subject.</para>
/// </remarks>
/// <value>The normalized subject.</value>
string NormalizedSubject { get; }
/// <summary>
/// Gets the Date header value.
/// </summary>
/// <remarks>
/// Gets the Date header value. If the Date header is not present, the arrival date is used.
/// If neither are known, <see cref="System.DateTimeOffset.MinValue"/> is returned.
/// </remarks>
/// <value>The date.</value>
DateTimeOffset Date { get; }
/// <summary>
/// Gets whether or not the message is a reply.
/// </summary>
/// <remarks>
/// This value should be based on whether the message subject contained any <c>"Re:"</c>, <c>"Re[#]:"</c> or <c>"FWD:"</c> prefixes.
/// </remarks>
/// <value><c>true</c> if the message is a reply; otherwise, <c>false</c>.</value>
bool IsReply { get; }
/// <summary>
/// Gets the message flags, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message flags, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Flags"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The message flags.</value>
MessageFlags? Flags { get; }
/// <summary>
/// Gets the user-defined message flags, if available.
/// </summary>
/// <remarks>
/// <para>Gets the user-defined message flags, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Flags"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The user-defined message flags.</value>
HashSet<string> Keywords { get; }
/// <summary>
/// Gets the user-defined message flags, if available.
/// </summary>
/// <remarks>
/// <para>Gets the user-defined message flags, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Flags"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The user-defined message flags.</value>
[Obsolete ("Use Keywords instead.")]
HashSet<string> UserFlags { get; }
/// <summary>
/// Gets the message annotations, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message annotations, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Annotations"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The message annotations.</value>
IList<Annotation> Annotations { get; }
/// <summary>
/// Gets the list of headers, if available.
/// </summary>
/// <remarks>
/// <para>Gets the list of headers, if available.</para>
/// <para>This property will only be set if <see cref="MessageSummaryItems.Headers"/>
/// is specified in a call to one of the
/// <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods or specific headers are requested via a one of the Fetch or FetchAsync methods
/// that accept list of specific headers to request for each message such as
/// <see cref="IMailFolder.Fetch(System.Collections.Generic.IList&lt;UniqueId&gt;,MessageSummaryItems,System.Collections.Generic.IEnumerable&lt;MimeKit.HeaderId&gt;,System.Threading.CancellationToken)"/>.
/// </para>
/// </remarks>
/// <value>The list of headers.</value>
HeaderList Headers { get; }
/// <summary>
/// Gets the internal date of the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the internal date of the message (often the same date as found in the <c>Received</c> header), if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.InternalDate"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The internal date of the message.</value>
DateTimeOffset? InternalDate { get; }
/// <summary>
/// Gets the size of the message, in bytes, if available.
/// </summary>
/// <remarks>
/// <para>Gets the size of the message, in bytes, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Size"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The size of the message.</value>
uint? Size { get; }
/// <summary>
/// Gets the mod-sequence value for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the mod-sequence value for the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.ModSeq"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The mod-sequence value.</value>
ulong? ModSeq { get; }
/// <summary>
/// Gets the message-ids that the message references, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message-ids that the message references, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.References"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The references.</value>
MessageIdList References { get; }
/// <summary>
/// Get the globally unique identifier for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the globally unique identifier of the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.EmailId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// <note type="info">This property maps to the <c>EMAILID</c> value defined in the
/// <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.</note>
/// </remarks>
/// <value>The globally unique message identifier.</value>
string EmailId { get; }
/// <summary>
/// Get the globally unique identifier for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the globally unique identifier of the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.EmailId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// <note type="info">This property maps to the <c>EMAILID</c> value defined in the
/// <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.</note>
/// </remarks>
/// <value>The globally unique message identifier.</value>
[Obsolete ("Use EmailId instead.")]
string Id { get; }
/// <summary>
/// Get the globally unique thread identifier for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the globally unique thread identifier for the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.ThreadId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// <note type="info">This property maps to the <c>THREADID</c> value defined in the
/// <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.</note>
/// </remarks>
/// <value>The globally unique thread identifier.</value>
string ThreadId { get; }
/// <summary>
/// Gets the unique identifier of the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the unique identifier of the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.UniqueId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The uid of the message.</value>
UniqueId UniqueId { get; }
/// <summary>
/// Gets the index of the message.
/// </summary>
/// <remarks>
/// <para>Gets the index of the message.</para>
/// <para>This property is always set.</para>
/// </remarks>
/// <value>The index of the message.</value>
int Index { get; }
#region GMail extension properties
/// <summary>
/// Gets the GMail message identifier, if available.
/// </summary>
/// <remarks>
/// <para>Gets the GMail message identifier, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.GMailMessageId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The GMail message identifier.</value>
ulong? GMailMessageId { get; }
/// <summary>
/// Gets the GMail thread identifier, if available.
/// </summary>
/// <remarks>
/// <para>Gets the GMail thread identifier, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.GMailThreadId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The GMail thread identifier.</value>
ulong? GMailThreadId { get; }
/// <summary>
/// Gets the list of GMail labels, if available.
/// </summary>
/// <remarks>
/// <para>Gets the list of GMail labels, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.GMailLabels"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The GMail labels.</value>
IList<string> GMailLabels { get; }
#endregion
}
}

View File

@ -0,0 +1,116 @@
//
// IProtocolLogger.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;
namespace MailKit {
/// <summary>
/// An interface for logging the communication between a client and server.
/// </summary>
/// <remarks>
/// An interface for logging the communication between a client and server.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\SmtpExamples.cs" region="ProtocolLogger" />
/// </example>
public interface IProtocolLogger : IDisposable
{
/// <summary>
/// Logs a connection to the specified URI.
/// </summary>
/// <remarks>
/// Logs a connection to the specified URI.
/// </remarks>
/// <param name="uri">The URI.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="uri"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The logger has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
void LogConnect (Uri uri);
/// <summary>
/// Logs a sequence of bytes sent by the client.
/// </summary>
/// <remarks>
/// <para>Logs a sequence of bytes sent by the client.</para>
/// <para><see cref="LogClient(byte[], int, int)"/> is called by the <see cref="IMailService"/> upon every successful
/// write operation to its underlying network stream, passing the exact same <paramref name="buffer"/>,
/// <paramref name="offset"/>, and <paramref name="count"/> arguments to the logging function.</para>
/// </remarks>
/// <param name='buffer'>The buffer to log.</param>
/// <param name='offset'>The offset of the first byte to log.</param>
/// <param name='count'>The number of bytes to log.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The logger has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
void LogClient (byte[] buffer, int offset, int count);
/// <summary>
/// Logs a sequence of bytes sent by the server.
/// </summary>
/// <remarks>
/// <para>Logs a sequence of bytes sent by the server.</para>
/// <para><see cref="LogServer(byte[], int, int)"/> is called by the <see cref="IMailService"/> upon every successful
/// read of its underlying network stream with the exact buffer that was read.</para>
/// </remarks>
/// <param name='buffer'>The buffer to log.</param>
/// <param name='offset'>The offset of the first byte to log.</param>
/// <param name='count'>The number of bytes to log.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="buffer"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <para><paramref name="offset"/> is less than zero or greater than the length of <paramref name="buffer"/>.</para>
/// <para>-or-</para>
/// <para>The <paramref name="buffer"/> is not large enough to contain <paramref name="count"/> bytes strting
/// at the specified <paramref name="offset"/>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The logger has been disposed.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
void LogServer (byte[] buffer, int offset, int count);
}
}

View File

@ -0,0 +1,58 @@
//
// ITransferProgress.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.
//
namespace MailKit {
/// <summary>
/// An interface for reporting progress of uploading or downloading messages.
/// </summary>
/// <remarks>
/// An interface for reporting progress of uploading or downloading messages.
/// </remarks>
public interface ITransferProgress
{
/// <summary>
/// Report the progress of the transfer operation.
/// </summary>
/// <remarks>
/// <para>Reports the progress of the transfer operation.</para>
/// <para>This method is only used if the operation knows the size
/// of the message, part, or stream being transferred without doing
/// extra work to calculate it.</para>
/// </remarks>
/// <param name="bytesTransferred">The number of bytes transferred.</param>
/// <param name="totalSize">The total size, in bytes, of the message, part, or stream being transferred.</param>
void Report (long bytesTransferred, long totalSize);
/// <summary>
/// Report the progress of the transfer operation.
/// </summary>
/// <remarks>
/// <para>Reports the progress of the transfer operation.</para>
/// </remarks>
/// <param name="bytesTransferred">The number of bytes transferred.</param>
void Report (long bytesTransferred);
}
}

16501
src/MailKit/MailFolder.cs Normal file

File diff suppressed because it is too large Load Diff

1582
src/MailKit/MailService.cs Normal file

File diff suppressed because it is too large Load Diff

1588
src/MailKit/MailSpool.cs Normal file

File diff suppressed because it is too large Load Diff

872
src/MailKit/MailStore.cs Normal file
View File

@ -0,0 +1,872 @@
//
// MailStore.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace MailKit {
/// <summary>
/// An abstract mail store implementation.
/// </summary>
/// <remarks>
/// An abstract mail store implementation.
/// </remarks>
public abstract class MailStore : MailService, IMailStore
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MailStore"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="MailKit.MailStore"/> class.
/// </remarks>
/// <param name="protocolLogger">The protocol logger.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="protocolLogger"/> is <c>null</c>.
/// </exception>
protected MailStore (IProtocolLogger protocolLogger) : base (protocolLogger)
{
}
/// <summary>
/// Gets the personal namespaces.
/// </summary>
/// <remarks>
/// The personal folder namespaces contain a user's personal mailbox folders.
/// </remarks>
/// <value>The personal namespaces.</value>
public abstract FolderNamespaceCollection PersonalNamespaces {
get;
}
/// <summary>
/// Gets the shared namespaces.
/// </summary>
/// <remarks>
/// The shared folder namespaces contain mailbox folders that are shared with the user.
/// </remarks>
/// <value>The shared namespaces.</value>
public abstract FolderNamespaceCollection SharedNamespaces {
get;
}
/// <summary>
/// Gets the other namespaces.
/// </summary>
/// <remarks>
/// The other folder namespaces contain other mailbox folders.
/// </remarks>
/// <value>The other namespaces.</value>
public abstract FolderNamespaceCollection OtherNamespaces {
get;
}
/// <summary>
/// Get whether or not the mail store supports quotas.
/// </summary>
/// <remarks>
/// Gets whether or not the mail store supports quotas.
/// </remarks>
/// <value><c>true</c> if the mail store supports quotas; otherwise, <c>false</c>.</value>
public abstract bool SupportsQuotas {
get;
}
/// <summary>
/// Get the threading algorithms supported by the mail store.
/// </summary>
/// <remarks>
/// The threading algorithms are queried as part of the
/// <a href="Overload_MailKit_MailStore_Connect.htm">Connect</a>
/// and <a href="Overload_MailKit_MailStore_Authenticate.htm">Authenticate</a> methods.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The supported threading algorithms.</value>
public abstract HashSet<ThreadingAlgorithm> ThreadingAlgorithms {
get;
}
/// <summary>
/// Get the Inbox folder.
/// </summary>
/// <remarks>
/// <para>The Inbox folder is the default folder and always exists on the mail store.</para>
/// <note type="note">This property will only be available after the client has been authenticated.</note>
/// </remarks>
/// <value>The Inbox folder.</value>
public abstract IMailFolder Inbox {
get;
}
/// <summary>
/// Enable the quick resynchronization feature.
/// </summary>
/// <remarks>
/// <para>Enables quick resynchronization when a folder is opened using the
/// <see cref="MailFolder.Open(FolderAccess,uint,ulong,System.Collections.Generic.IList&lt;UniqueId&gt;,System.Threading.CancellationToken)"/>
/// method.</para>
/// <para>If this feature is enabled, the <see cref="MailFolder.MessageExpunged"/> event is replaced
/// with the <see cref="MailFolder.MessagesVanished"/> event.</para>
/// <para>This method needs to be called immediately after calling one of the
/// <a href="Overload_MailKit_MailService_Authenticate.htm">Authenticate</a> methods, before
/// opening any folders.</para>
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Quick resynchronization needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The mail store does not support quick resynchronization.
/// </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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract void EnableQuickResync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously enable the quick resynchronization feature.
/// </summary>
/// <remarks>
/// <para>Enables quick resynchronization when a folder is opened using the
/// <see cref="MailFolder.Open(FolderAccess,uint,ulong,System.Collections.Generic.IList&lt;UniqueId&gt;,System.Threading.CancellationToken)"/>
/// method.</para>
/// <para>If this feature is enabled, the <see cref="MailFolder.MessageExpunged"/> event is replaced
/// with the <see cref="MailFolder.MessagesVanished"/> event.</para>
/// <para>This method needs to be called immediately after calling one of the
/// <a href="Overload_MailKit_MailService_Authenticate.htm">Authenticate</a> methods, before
/// opening any folders.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Quick resynchronization needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The mail store does not support quick resynchronization.
/// </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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract Task EnableQuickResyncAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the specified special folder.
/// </summary>
/// <remarks>
/// Not all mail stores support special folders. Each implementation
/// should provide a way to determine if special folders are supported.
/// </remarks>
/// <returns>The folder if available; otherwise <c>null</c>.</returns>
/// <param name="folder">The type of special folder.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="folder"/> is out of range.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> is not authenticated.
/// </exception>
public abstract IMailFolder GetFolder (SpecialFolder folder);
/// <summary>
/// Get the folder for the specified namespace.
/// </summary>
/// <remarks>
/// Gets the folder for the specified namespace.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="namespace">The namespace.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> is not authenticated.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
public abstract IMailFolder GetFolder (FolderNamespace @namespace);
/// <summary>
/// Get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> 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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public virtual IList<IMailFolder> GetFolders (FolderNamespace @namespace, bool subscribedOnly, CancellationToken cancellationToken = default (CancellationToken))
{
return GetFolders (@namespace, StatusItems.None, subscribedOnly, cancellationToken);
}
/// <summary>
/// Asynchronously get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Asynchronously gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> 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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public virtual Task<IList<IMailFolder>> GetFoldersAsync (FolderNamespace @namespace, bool subscribedOnly, CancellationToken cancellationToken = default (CancellationToken))
{
return GetFoldersAsync (@namespace, StatusItems.None, subscribedOnly, cancellationToken);
}
/// <summary>
/// Get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="items">The status items to pre-populate.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> 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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract IList<IMailFolder> GetFolders (FolderNamespace @namespace, StatusItems items = StatusItems.None, bool subscribedOnly = false, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Asynchronously gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="items">The status items to pre-populate.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> 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="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract Task<IList<IMailFolder>> GetFoldersAsync (FolderNamespace @namespace, StatusItems items = StatusItems.None, bool subscribedOnly = false, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the folder for the specified path.
/// </summary>
/// <remarks>
/// Gets the folder for the specified path.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="path">The folder path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract IMailFolder GetFolder (string path, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the folder for the specified path.
/// </summary>
/// <remarks>
/// Asynchronously gets the folder for the specified path.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="path">The folder path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="MailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract Task<IMailFolder> GetFolderAsync (string path, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata value.</returns>
/// <param name="tag">The metadata tag.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract string GetMetadata (MetadataTag tag, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata value.</returns>
/// <param name="tag">The metadata tag.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract Task<string> GetMetadataAsync (MetadataTag tag, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="tags"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public virtual MetadataCollection GetMetadata (IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken))
{
return GetMetadata (new MetadataOptions (), tags, cancellationToken);
}
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="tags"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public virtual Task<MetadataCollection> GetMetadataAsync (IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken))
{
return GetMetadataAsync (new MetadataOptions (), tags, cancellationToken);
}
/// <summary>
/// Gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="options">The metadata options.</param>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="tags"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract MetadataCollection GetMetadata (MetadataOptions options, IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="options">The metadata options.</param>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="tags"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract Task<MetadataCollection> GetMetadataAsync (MetadataOptions options, IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Sets the specified metadata.
/// </summary>
/// <remarks>
/// Sets the specified metadata.
/// </remarks>
/// <param name="metadata">The metadata.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="metadata"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract void SetMetadata (MetadataCollection metadata, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously sets the specified metadata.
/// </summary>
/// <remarks>
/// Asynchronously sets the specified metadata.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="metadata">The metadata.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="metadata"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="IMailStore"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="IMailStore"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// The <see cref="IMailStore"/> is not authenticated.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The folder does not support metadata.
/// </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="ProtocolException">
/// The server's response contained unexpected tokens.
/// </exception>
/// <exception cref="CommandException">
/// The command failed.
/// </exception>
public abstract Task SetMetadataAsync (MetadataCollection metadata, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Occurs when a remote message store receives an alert message from the server.
/// </summary>
/// <remarks>
/// The <see cref="Alert"/> event is raised whenever the mail server sends an
/// alert message.
/// </remarks>
public event EventHandler<AlertEventArgs> Alert;
/// <summary>
/// Raise the alert event.
/// </summary>
/// <remarks>
/// Raises the alert event.
/// </remarks>
/// <param name="message">The alert message.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="message"/> is <c>null</c>.
/// </exception>
protected virtual void OnAlert (string message)
{
var handler = Alert;
if (handler != null)
handler (this, new AlertEventArgs (message));
}
/// <summary>
/// Occurs when a folder is created.
/// </summary>
/// <remarks>
/// The <see cref="FolderCreated"/> event is emitted when a new folder is created.
/// </remarks>
public event EventHandler<FolderCreatedEventArgs> FolderCreated;
/// <summary>
/// Raise the folder created event.
/// </summary>
/// <remarks>
/// Raises the folder created event.
/// </remarks>
/// <param name="folder">The folder that was just created.</param>
protected virtual void OnFolderCreated (IMailFolder folder)
{
var handler = FolderCreated;
if (handler != null)
handler (this, new FolderCreatedEventArgs (folder));
}
/// <summary>
/// Occurs when metadata changes.
/// </summary>
/// <remarks>
/// The <see cref="MetadataChanged"/> event is emitted when metadata changes.
/// </remarks>
public event EventHandler<MetadataChangedEventArgs> MetadataChanged;
/// <summary>
/// Raise the metadata changed event.
/// </summary>
/// <remarks>
/// Raises the metadata changed event.
/// </remarks>
/// <param name="metadata">The metadata that changed.</param>
protected virtual void OnMetadataChanged (Metadata metadata)
{
var handler = MetadataChanged;
if (handler != null)
handler (this, new MetadataChangedEventArgs (metadata));
}
}
}

View File

@ -0,0 +1,507 @@
//
// MailTransport.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using MimeKit;
namespace MailKit {
/// <summary>
/// An abstract mail transport implementation.
/// </summary>
/// <remarks>
/// An abstract mail transport implementation.
/// </remarks>
public abstract class MailTransport : MailService, IMailTransport
{
static readonly FormatOptions DefaultOptions;
static MailTransport ()
{
var options = FormatOptions.Default.Clone ();
options.HiddenHeaders.Add (HeaderId.ContentLength);
options.HiddenHeaders.Add (HeaderId.ResentBcc);
options.HiddenHeaders.Add (HeaderId.Bcc);
options.NewLineFormat = NewLineFormat.Dos;
DefaultOptions = options;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MailTransport"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="MailKit.MailTransport"/> class.
/// </remarks>
/// <param name="protocolLogger">The protocol logger.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="protocolLogger"/> is <c>null</c>.
/// </exception>
protected MailTransport (IProtocolLogger protocolLogger) : base (protocolLogger)
{
}
/// <summary>
/// Send the specified message.
/// </summary>
/// <remarks>
/// <para>Sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\SmtpExamples.cs" region="SendMessage"/>
/// </example>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="message"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public virtual void Send (MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
{
Send (DefaultOptions, message, cancellationToken, progress);
}
/// <summary>
/// Asynchronously send the specified message.
/// </summary>
/// <remarks>
/// <para>Asynchronously sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="message"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public virtual Task SendAsync (MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
{
return SendAsync (DefaultOptions, message, cancellationToken, progress);
}
/// <summary>
/// Send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="sender"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="recipients"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public virtual void Send (MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
{
Send (DefaultOptions, message, sender, recipients, cancellationToken, progress);
}
/// <summary>
/// Asynchronously send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Asynchronously sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="sender"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="recipients"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public virtual Task SendAsync (MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null)
{
return SendAsync (DefaultOptions, message, sender, recipients, cancellationToken, progress);
}
/// <summary>
/// Send the specified message.
/// </summary>
/// <remarks>
/// <para>Sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\SmtpExamples.cs" region="SendMessageWithOptions"/>
/// </example>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>Internationalized formatting was requested but is not supported by the transport.</para>
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public abstract void Send (FormatOptions options, MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously send the specified message.
/// </summary>
/// <remarks>
/// <para>Asynchronously sends the specified message.</para>
/// <para>The sender address is determined by checking the following
/// message headers (in order of precedence): Resent-Sender,
/// Resent-From, Sender, and From.</para>
/// <para>If either the Resent-Sender or Resent-From addresses are present,
/// the recipients are collected from the Resent-To, Resent-Cc, and
/// Resent-Bcc headers, otherwise the To, Cc, and Bcc headers are used.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>Internationalized formatting was requested but is not supported by the transport.</para>
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public abstract Task SendAsync (FormatOptions options, MimeMessage message, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="sender"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="recipients"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>Internationalized formatting was requested but is not supported by the transport.</para>
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public abstract void Send (FormatOptions options, MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Asynchronously send the specified message using the supplied sender and recipients.
/// </summary>
/// <remarks>
/// Asynchronously sends the specified message using the supplied sender and recipients.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="sender">The mailbox address to use for sending the message.</param>
/// <param name="recipients">The mailbox addresses that should receive the message.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress reporting mechanism.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="sender"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="recipients"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="MailTransport"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="MailTransport"/> is not connected.
/// </exception>
/// <exception cref="ServiceNotAuthenticatedException">
/// Authentication is required before sending a message.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// <para>A sender has not been specified.</para>
/// <para>-or-</para>
/// <para>No recipients have been specified.</para>
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation has been canceled.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>Internationalized formatting was requested but is not supported by the transport.</para>
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="CommandException">
/// The send command failed.
/// </exception>
/// <exception cref="ProtocolException">
/// A protocol exception occurred.
/// </exception>
public abstract Task SendAsync (FormatOptions options, MimeMessage message, MailboxAddress sender, IEnumerable<MailboxAddress> recipients, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Occurs when a message is successfully sent via the transport.
/// </summary>
/// <remarks>
/// The <see cref="MessageSent"/> event will be emitted each time a message is successfully sent.
/// </remarks>
public event EventHandler<MessageSentEventArgs> MessageSent;
/// <summary>
/// Raise the message sent event.
/// </summary>
/// <remarks>
/// Raises the message sent event.
/// </remarks>
/// <param name="e">The message sent event args.</param>
protected virtual void OnMessageSent (MessageSentEventArgs e)
{
var handler = MessageSent;
if (handler != null)
handler (this, e);
}
}
}

View File

@ -0,0 +1,98 @@
//
// MessageEventArgs.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;
namespace MailKit {
/// <summary>
/// Event args used when the state of a message changes.
/// </summary>
/// <remarks>
/// Event args used when the state of a message changes.
/// </remarks>
public class MessageEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.MessageEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageEventArgs (int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException (nameof (index));
Index = index;
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.MessageEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageEventArgs (int index, UniqueId uid)
{
if (index < 0)
throw new ArgumentOutOfRangeException (nameof (index));
Index = index;
UniqueId = uid;
}
/// <summary>
/// Gets the index of the message that changed.
/// </summary>
/// <remarks>
/// Gets the index of the message that changed.
/// </remarks>
/// <value>The index of the message.</value>
public int Index {
get; private set;
}
/// <summary>
/// Gets the unique ID of the message that changed, if available.
/// </summary>
/// <remarks>
/// Gets the unique ID of the message that changed, if available.
/// </remarks>
/// <value>The unique ID of the message.</value>
public UniqueId? UniqueId {
get; internal set;
}
}
}

View File

@ -0,0 +1,78 @@
//
// MessageFlags.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;
namespace MailKit {
/// <summary>
/// An enumeration of message flags.
/// </summary>
/// <remarks>
/// An enumeration of message flags.
/// </remarks>
[Flags]
public enum MessageFlags {
/// <summary>
/// No message flags are set.
/// </summary>
None = 0,
/// <summary>
/// The message has been read.
/// </summary>
Seen = 1 << 0,
/// <summary>
/// The message has been answered (replied to).
/// </summary>
Answered = 1 << 1,
/// <summary>
/// The message has been flagged for importance.
/// </summary>
Flagged = 1 << 2,
/// <summary>
/// The message has been marked for deletion.
/// </summary>
Deleted = 1 << 3,
/// <summary>
/// The message is marked as a draft.
/// </summary>
Draft = 1 << 4,
/// <summary>
/// The message has just recently arrived in the folder.
/// </summary>
Recent = 1 << 5,
/// <summary>
/// User-defined flags are allowed by the folder.
/// </summary>
UserDefined = 1 << 6,
}
}

View File

@ -0,0 +1,269 @@
//
// MessageFlagsChangedEventArgs.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.Collections.Generic;
namespace MailKit {
/// <summary>
/// Event args for the <see cref="IMailFolder.MessageFlagsChanged"/> event.
/// </summary>
/// <remarks>
/// Event args for the <see cref="IMailFolder.MessageFlagsChanged"/> event.
/// </remarks>
public class MessageFlagsChangedEventArgs : MessageEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
internal MessageFlagsChangedEventArgs (int index) : base (index)
{
Keywords = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="flags">The message flags.</param>
public MessageFlagsChangedEventArgs (int index, MessageFlags flags) : base (index)
{
Keywords = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="flags">The message flags.</param>
/// <param name="keywords">The user-defined message flags.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="keywords"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, MessageFlags flags, HashSet<string> keywords) : base (index)
{
if (keywords == null)
throw new ArgumentNullException (nameof (keywords));
Keywords = keywords;
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="flags">The message flags.</param>
/// <param name="modseq">The modification sequence value.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, MessageFlags flags, ulong modseq) : base (index)
{
Keywords = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
ModSeq = modseq;
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="flags">The message flags.</param>
/// <param name="keywords">The user-defined message flags.</param>
/// <param name="modseq">The modification sequence value.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="keywords"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, MessageFlags flags, HashSet<string> keywords, ulong modseq) : base (index)
{
if (keywords == null)
throw new ArgumentNullException (nameof (keywords));
Keywords = keywords;
ModSeq = modseq;
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="flags">The message flags.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, UniqueId uid, MessageFlags flags) : base (index, uid)
{
Keywords = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="flags">The message flags.</param>
/// <param name="keywords">The user-defined message flags.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="keywords"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, UniqueId uid, MessageFlags flags, HashSet<string> keywords) : base (index, uid)
{
if (keywords == null)
throw new ArgumentNullException (nameof (keywords));
Keywords = keywords;
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="flags">The message flags.</param>
/// <param name="modseq">The modification sequence value.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, UniqueId uid, MessageFlags flags, ulong modseq) : base (index, uid)
{
Keywords = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
ModSeq = modseq;
Flags = flags;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="flags">The message flags.</param>
/// <param name="keywords">The user-defined message flags.</param>
/// <param name="modseq">The modification sequence value.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="keywords"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageFlagsChangedEventArgs (int index, UniqueId uid, MessageFlags flags, HashSet<string> keywords, ulong modseq) : base (index, uid)
{
if (keywords == null)
throw new ArgumentNullException (nameof (keywords));
Keywords = keywords;
ModSeq = modseq;
Flags = flags;
}
/// <summary>
/// Gets the updated message flags.
/// </summary>
/// <remarks>
/// Gets the updated message flags.
/// </remarks>
/// <value>The updated message flags.</value>
public MessageFlags Flags {
get; internal set;
}
/// <summary>
/// Gets the updated user-defined message flags.
/// </summary>
/// <remarks>
/// Gets the updated user-defined message flags.
/// </remarks>
/// <value>The updated user-defined message flags.</value>
public HashSet<string> Keywords {
get; private set;
}
/// <summary>
/// Gets the updated user-defined message flags.
/// </summary>
/// <remarks>
/// Gets the updated user-defined message flags.
/// </remarks>
/// <value>The updated user-defined message flags.</value>
[Obsolete ("Use Keywords instead.")]
public HashSet<string> UserFlags {
get { return Keywords; }
}
/// <summary>
/// Gets the updated mod-sequence value of the message, if available.
/// </summary>
/// <remarks>
/// Gets the updated mod-sequence value of the message, if available.
/// </remarks>
/// <value>The mod-sequence value.</value>
public ulong? ModSeq {
get; internal set;
}
}
}

View File

@ -0,0 +1,170 @@
//
// LabelsChangedEventArgs.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.Collections.Generic;
using System.Collections.ObjectModel;
namespace MailKit {
/// <summary>
/// Event args for the <see cref="IMailFolder.MessageLabelsChanged"/> event.
/// </summary>
/// <remarks>
/// Event args for the <see cref="IMailFolder.MessageLabelsChanged"/> event.
/// </remarks>
public class MessageLabelsChangedEventArgs : MessageEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageLabelsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageLabelsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
internal MessageLabelsChangedEventArgs (int index) : base (index)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageLabelsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageLabelsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="labels">The message labels.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="labels"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageLabelsChangedEventArgs (int index, IList<string> labels) : base (index)
{
if (labels == null)
throw new ArgumentNullException (nameof (labels));
Labels = new ReadOnlyCollection<string> (labels);
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageLabelsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageLabelsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="labels">The message labels.</param>
/// <param name="modseq">The modification sequence value.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="labels"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageLabelsChangedEventArgs (int index, IList<string> labels, ulong modseq) : base (index)
{
if (labels == null)
throw new ArgumentNullException (nameof (labels));
Labels = new ReadOnlyCollection<string> (labels);
ModSeq = modseq;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageLabelsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageLabelsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="labels">The message labels.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="labels"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageLabelsChangedEventArgs (int index, UniqueId uid, IList<string> labels) : base (index, uid)
{
if (labels == null)
throw new ArgumentNullException (nameof (labels));
Labels = new ReadOnlyCollection<string> (labels);
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageLabelsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageLabelsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="labels">The message labels.</param>
/// <param name="modseq">The modification sequence value.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="labels"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is out of range.
/// </exception>
public MessageLabelsChangedEventArgs (int index, UniqueId uid, IList<string> labels, ulong modseq) : base (index, uid)
{
if (labels == null)
throw new ArgumentNullException (nameof (labels));
Labels = new ReadOnlyCollection<string> (labels);
ModSeq = modseq;
}
/// <summary>
/// Gets the updated labels.
/// </summary>
/// <remarks>
/// Gets the updated labels.
/// </remarks>
/// <value>The updated labels.</value>
public IList<string> Labels {
get; internal set;
}
/// <summary>
/// Gets the updated mod-sequence value of the message, if available.
/// </summary>
/// <remarks>
/// Gets the updated mod-sequence value of the message, if available.
/// </remarks>
/// <value>The mod-sequence value.</value>
public ulong? ModSeq {
get; internal set;
}
}
}

View File

@ -0,0 +1,92 @@
//
// MessageNotFoundException.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;
#if SERIALIZABLE
using System.Security;
using System.Runtime.Serialization;
#endif
namespace MailKit {
/// <summary>
/// The exception that is thrown when a message (or body part) could not be found.
/// </summary>
/// <remarks>
/// This exception is thrown by methods such as
/// <a href="Overload_MailKit_IMailFolder_GetMessage.htm">IMailFolder.GetMessage</a>,
/// <a href="Overload_MailKit_IMailFolder_GetBodyPart.htm">IMailFolder.GetBodyPart</a>, or
/// <a href="Overload_MailKit_IMailFolder_GetStream.htm">IMailFolder.GetStream</a>
/// when the server's response does not contain the message, body part, or stream data requested.
/// </remarks>
#if SERIALIZABLE
[Serializable]
#endif
public class MessageNotFoundException : Exception
{
#if SERIALIZABLE
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Deserializes a <see cref="MessageNotFoundException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
[SecuritySafeCritical]
protected MessageNotFoundException (SerializationInfo info, StreamingContext context) : base (info, context)
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageNotFoundException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
/// <param name="innerException">The inner exception.</param>
/// <exception cref="System.ArgumentNullException">
/// </exception>
public MessageNotFoundException (string message, Exception innerException) : base (message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageNotFoundException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageNotFoundException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
public MessageNotFoundException (string message) : base (message)
{
}
}
}

View File

@ -0,0 +1,87 @@
//
// MessageSentEventArgs.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 MimeKit;
namespace MailKit {
/// <summary>
/// Event args used when a message is successfully sent.
/// </summary>
/// <remarks>
/// Event args used when message is successfully sent.
/// </remarks>
public class MessageSentEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageSentEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageSentEventArgs"/>.
/// </remarks>
/// <param name="message">The message that was just sent.</param>
/// <param name="response">The response from the server.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="message"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="response"/> is <c>null</c>.</para>
/// </exception>
public MessageSentEventArgs (MimeMessage message, string response)
{
if (message == null)
throw new ArgumentNullException (nameof (message));
if (response == null)
throw new ArgumentNullException (nameof (response));
Message = message;
Response = response;
}
/// <summary>
/// Get the message that was just sent.
/// </summary>
/// <remarks>
/// Gets the message that was just sent.
/// </remarks>
/// <value>The message.</value>
public MimeMessage Message {
get; private set;
}
/// <summary>
/// Get the server's response.
/// </summary>
/// <remarks>
/// Gets the server's response.
/// </remarks>
/// <value>The response.</value>
public string Response {
get; private set;
}
}
}

View File

@ -0,0 +1,295 @@
//
// MessageSorter.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.Linq;
using System.Collections.Generic;
using MimeKit;
using MailKit.Search;
namespace MailKit {
/// <summary>
/// Routines for sorting messages.
/// </summary>
/// <remarks>
/// Routines for sorting messages.
/// </remarks>
public static class MessageSorter
{
class MessageComparer<T> : IComparer<T> where T : IMessageSummary
{
readonly IList<OrderBy> orderBy;
public MessageComparer (IList<OrderBy> orderBy)
{
this.orderBy = orderBy;
}
#region IComparer implementation
static int CompareDisplayNames (InternetAddressList list1, InternetAddressList list2)
{
var m1 = list1.Mailboxes.GetEnumerator ();
var m2 = list2.Mailboxes.GetEnumerator ();
bool n1 = m1.MoveNext ();
bool n2 = m2.MoveNext ();
while (n1 && n2) {
var name1 = m1.Current.Name ?? string.Empty;
var name2 = m2.Current.Name ?? string.Empty;
int cmp;
if ((cmp = string.Compare (name1, name2, StringComparison.OrdinalIgnoreCase)) != 0)
return cmp;
n1 = m1.MoveNext ();
n2 = m2.MoveNext ();
}
return n1 ? 1 : (n2 ? -1 : 0);
}
static int CompareMailboxAddresses (InternetAddressList list1, InternetAddressList list2)
{
var m1 = list1.Mailboxes.GetEnumerator ();
var m2 = list2.Mailboxes.GetEnumerator ();
bool n1 = m1.MoveNext ();
bool n2 = m2.MoveNext ();
while (n1 && n2) {
int cmp;
if ((cmp = string.Compare (m1.Current.Address, m2.Current.Address, StringComparison.OrdinalIgnoreCase)) != 0)
return cmp;
n1 = m1.MoveNext ();
n2 = m2.MoveNext ();
}
return n1 ? 1 : (n2 ? -1 : 0);
}
public int Compare (T x, T y)
{
int cmp = 0;
for (int i = 0; i < orderBy.Count; i++) {
switch (orderBy[i].Type) {
case OrderByType.Annotation:
var annotation = (OrderByAnnotation) orderBy[i];
var xannotation = x.Annotations?.FirstOrDefault (a => a.Entry == annotation.Entry);
var yannotation = y.Annotations?.FirstOrDefault (a => a.Entry == annotation.Entry);
var xvalue = xannotation?.Properties[annotation.Attribute] ?? string.Empty;
var yvalue = yannotation?.Properties[annotation.Attribute] ?? string.Empty;
cmp = string.Compare (xvalue, yvalue, StringComparison.OrdinalIgnoreCase);
break;
case OrderByType.Arrival:
cmp = x.Index.CompareTo (y.Index);
break;
case OrderByType.Cc:
cmp = CompareMailboxAddresses (x.Envelope.Cc, y.Envelope.Cc);
break;
case OrderByType.Date:
cmp = x.Date.CompareTo (y.Date);
break;
case OrderByType.DisplayFrom:
cmp = CompareDisplayNames (x.Envelope.From, y.Envelope.From);
break;
case OrderByType.From:
cmp = CompareMailboxAddresses (x.Envelope.From, y.Envelope.From);
break;
case OrderByType.ModSeq:
var xmodseq = x.ModSeq ?? 0;
var ymodseq = y.ModSeq ?? 0;
cmp = xmodseq.CompareTo (ymodseq);
break;
case OrderByType.Size:
var xsize = x.Size ?? 0;
var ysize = y.Size ?? 0;
cmp = xsize.CompareTo (ysize);
break;
case OrderByType.Subject:
var xsubject = x.Envelope.Subject ?? string.Empty;
var ysubject = y.Envelope.Subject ?? string.Empty;
cmp = string.Compare (xsubject, ysubject, StringComparison.OrdinalIgnoreCase);
break;
case OrderByType.DisplayTo:
cmp = CompareDisplayNames (x.Envelope.To, y.Envelope.To);
break;
case OrderByType.To:
cmp = CompareMailboxAddresses (x.Envelope.To, y.Envelope.To);
break;
}
if (cmp == 0)
continue;
return orderBy[i].Order == SortOrder.Descending ? cmp * -1 : cmp;
}
return cmp;
}
#endregion
}
static MessageSummaryItems GetMessageSummaryItems (IList<OrderBy> orderBy)
{
var items = MessageSummaryItems.None;
for (int i = 0; i < orderBy.Count; i++) {
switch (orderBy[i].Type) {
case OrderByType.Annotation:
items |= MessageSummaryItems.Annotations;
break;
case OrderByType.Arrival:
break;
case OrderByType.Cc:
case OrderByType.Date:
case OrderByType.DisplayFrom:
case OrderByType.DisplayTo:
case OrderByType.From:
case OrderByType.Subject:
case OrderByType.To:
items |= MessageSummaryItems.Envelope;
break;
case OrderByType.ModSeq:
items |= MessageSummaryItems.ModSeq;
break;
case OrderByType.Size:
items |= MessageSummaryItems.Size;
break;
}
}
return items;
}
/// <summary>
/// Sorts the messages by the specified ordering.
/// </summary>
/// <remarks>
/// Sorts the messages by the specified ordering.
/// </remarks>
/// <returns>The sorted messages.</returns>
/// <typeparam name="T">The message items must implement the <see cref="IMessageSummary"/> interface.</typeparam>
/// <param name="messages">The messages to sort.</param>
/// <param name="orderBy">The sort ordering.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="messages"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="orderBy"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para><paramref name="messages"/> contains one or more items that is missing information needed for sorting.</para>
/// <para>-or-</para>
/// <para><paramref name="orderBy"/> is an empty list.</para>
/// </exception>
public static IList<T> Sort<T> (this IEnumerable<T> messages, IList<OrderBy> orderBy) where T : IMessageSummary
{
if (messages == null)
throw new ArgumentNullException (nameof (messages));
if (orderBy == null)
throw new ArgumentNullException (nameof (orderBy));
if (orderBy.Count == 0)
throw new ArgumentException ("No sort order provided.", nameof (orderBy));
var requiredFields = GetMessageSummaryItems (orderBy);
var list = new List<T> ();
foreach (var message in messages) {
if ((message.Fields & requiredFields) != requiredFields)
throw new ArgumentException ("One or more messages is missing information needed for sorting.", nameof (messages));
list.Add (message);
}
if (list.Count < 2)
return list;
var comparer = new MessageComparer<T> (orderBy);
list.Sort (comparer);
return list;
}
/// <summary>
/// Sorts the messages by the specified ordering.
/// </summary>
/// <remarks>
/// Sorts the messages by the specified ordering.
/// </remarks>
/// <returns>The sorted messages.</returns>
/// <typeparam name="T">The message items must implement the <see cref="IMessageSummary"/> interface.</typeparam>
/// <param name="messages">The messages to sort.</param>
/// <param name="orderBy">The sort ordering.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="messages"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="orderBy"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para><paramref name="messages"/> contains one or more items that is missing information needed for sorting.</para>
/// <para>-or-</para>
/// <para><paramref name="orderBy"/> is an empty list.</para>
/// </exception>
public static void Sort<T> (this List<T> messages, IList<OrderBy> orderBy) where T : IMessageSummary
{
if (messages == null)
throw new ArgumentNullException (nameof (messages));
if (orderBy == null)
throw new ArgumentNullException (nameof (orderBy));
if (orderBy.Count == 0)
throw new ArgumentException ("No sort order provided.", nameof (orderBy));
var requiredFields = GetMessageSummaryItems (orderBy);
for (int i = 0; i < messages.Count; i++) {
if ((messages[i].Fields & requiredFields) != requiredFields)
throw new ArgumentException ("One or more messages is missing information needed for sorting.", nameof (messages));
}
if (messages.Count < 2)
return;
var comparer = new MessageComparer<T> (orderBy);
messages.Sort (comparer);
}
}
}

View File

@ -0,0 +1,758 @@
//
// MessageSummary.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.Linq;
using System.Collections.Generic;
using MimeKit;
using MimeKit.Utils;
namespace MailKit {
/// <summary>
/// A summary of a message.
/// </summary>
/// <remarks>
/// <para>The <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a> and
/// <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a> methods
/// return lists of <see cref="IMessageSummary"/> items.</para>
/// <para>The properties of the <see cref="MessageSummary"/> that will be available
/// depend on the <see cref="MessageSummaryItems"/> passed to the aformentioned method.</para>
/// </remarks>
public class MessageSummary : IMessageSummary
{
int threadableReplyDepth = -1;
string normalizedSubject;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageSummary"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageSummary"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is negative.
/// </exception>
public MessageSummary (int index)
{
if (index < 0)
throw new ArgumentOutOfRangeException (nameof (index));
Keywords = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
Index = index;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageSummary"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageSummary"/>.
/// </remarks>
/// <param name="folder">The folder that the message belongs to.</param>
/// <param name="index">The message index.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folder"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="index"/> is negative.
/// </exception>
public MessageSummary (IMailFolder folder, int index) : this (index)
{
if (folder == null)
throw new ArgumentNullException (nameof (folder));
Folder = folder;
}
void UpdateThreadableSubject ()
{
if (normalizedSubject != null)
return;
if (Envelope?.Subject != null) {
normalizedSubject = MessageThreader.GetThreadableSubject (Envelope.Subject, out threadableReplyDepth);
} else {
normalizedSubject = string.Empty;
threadableReplyDepth = 0;
}
}
/// <summary>
/// Get the folder that the message belongs to.
/// </summary>
/// <remarks>
/// Gets the folder that the message belongs to, if available.
/// </remarks>
/// <value>The folder.</value>
public IMailFolder Folder {
get; private set;
}
/// <summary>
/// Get a bitmask of fields that have been populated.
/// </summary>
/// <remarks>
/// Gets a bitmask of fields that have been populated.
/// </remarks>
/// <value>The fields that have been populated.</value>
public MessageSummaryItems Fields {
get; internal set;
}
/// <summary>
/// Gets the body structure of the message, if available.
/// </summary>
/// <remarks>
/// <para>The body will be one of <see cref="BodyPartText"/>,
/// <see cref="BodyPartMessage"/>, <see cref="BodyPartBasic"/>,
/// or <see cref="BodyPartMultipart"/>.</para>
/// <para>This property will only be set if either the
/// <see cref="MessageSummaryItems.Body"/> flag or the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The body structure of the message.</value>
public BodyPart Body {
get; set;
}
static BodyPart GetMultipartRelatedRoot (BodyPartMultipart related)
{
string start = related.ContentType.Parameters["start"];
string contentId;
if (start == null)
return related.BodyParts.Count > 0 ? related.BodyParts[0] : null;
if ((contentId = MimeUtils.EnumerateReferences (start).FirstOrDefault ()) == null)
contentId = start;
var cid = new Uri (string.Format ("cid:{0}", contentId));
for (int i = 0; i < related.BodyParts.Count; i++) {
var basic = related.BodyParts[i] as BodyPartBasic;
if (basic != null && (basic.ContentId == contentId || basic.ContentLocation == cid))
return basic;
var multipart = related.BodyParts[i] as BodyPartMultipart;
if (multipart != null && multipart.ContentLocation == cid)
return multipart;
}
return null;
}
static bool TryGetMultipartAlternativeBody (BodyPartMultipart multipart, bool html, out BodyPartText body)
{
// walk the multipart/alternative children backwards from greatest level of faithfulness to the least faithful
for (int i = multipart.BodyParts.Count - 1; i >= 0; i--) {
var multi = multipart.BodyParts[i] as BodyPartMultipart;
BodyPartText text = null;
if (multi != null) {
if (multi.ContentType.IsMimeType ("multipart", "related")) {
text = GetMultipartRelatedRoot (multi) as BodyPartText;
} else if (multi.ContentType.IsMimeType ("multipart", "alternative")) {
// Note: nested multipart/alternatives make no sense... yet here we are.
if (TryGetMultipartAlternativeBody (multi, html, out body))
return true;
}
} else {
text = multipart.BodyParts[i] as BodyPartText;
}
if (text != null && (html ? text.IsHtml : text.IsPlain)) {
body = text;
return true;
}
}
body = null;
return false;
}
static bool TryGetMessageBody (BodyPartMultipart multipart, bool html, out BodyPartText body)
{
BodyPartMultipart multi;
BodyPartText text;
if (multipart.ContentType.IsMimeType ("multipart", "alternative"))
return TryGetMultipartAlternativeBody (multipart, html, out body);
if (!multipart.ContentType.IsMimeType ("multipart", "related")) {
// Note: This is probably a multipart/mixed... and if not, we can still treat it like it is.
for (int i = 0; i < multipart.BodyParts.Count; i++) {
multi = multipart.BodyParts[i] as BodyPartMultipart;
// descend into nested multiparts, if there are any...
if (multi != null) {
if (TryGetMessageBody (multi, html, out body))
return true;
// The text body should never come after a multipart.
break;
}
text = multipart.BodyParts[i] as BodyPartText;
// Look for the first non-attachment text part (realistically, the body text will
// preceed any attachments, but I'm not sure we can rely on that assumption).
if (text != null && !text.IsAttachment) {
if (html ? text.IsHtml : text.IsPlain) {
body = text;
return true;
}
// Note: the first text/* part in a multipart/mixed is the text body.
// If it's not in the format we're looking for, then it doesn't exist.
break;
}
}
} else {
// Note: If the multipart/related root document is HTML, then this is the droid we are looking for.
var root = GetMultipartRelatedRoot (multipart);
text = root as BodyPartText;
if (text != null) {
body = (html ? text.IsHtml : text.IsPlain) ? text : null;
return body != null;
}
// maybe the root is another multipart (like multipart/alternative)?
multi = root as BodyPartMultipart;
if (multi != null)
return TryGetMessageBody (multi, html, out body);
}
body = null;
return false;
}
/// <summary>
/// Gets the text body part of the message if it exists.
/// </summary>
/// <remarks>
/// <para>Gets the <c>text/plain</c> body part of the message.</para>
/// <para>This property will only be usable if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
/// <value>The text body if it exists; otherwise, <c>null</c>.</value>
public BodyPartText TextBody {
get {
var multipart = Body as BodyPartMultipart;
if (multipart != null) {
BodyPartText plain;
if (TryGetMessageBody (multipart, false, out plain))
return plain;
} else {
var text = Body as BodyPartText;
if (text != null && text.IsPlain)
return text;
}
return null;
}
}
/// <summary>
/// Gets the html body part of the message if it exists.
/// </summary>
/// <remarks>
/// <para>Gets the <c>text/html</c> body part of the message.</para>
/// <para>This property will only be usable if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The html body if it exists; otherwise, <c>null</c>.</value>
public BodyPartText HtmlBody {
get {
var multipart = Body as BodyPartMultipart;
if (multipart != null) {
BodyPartText html;
if (TryGetMessageBody (multipart, true, out html))
return html;
} else {
var text = Body as BodyPartText;
if (text != null && text.IsHtml)
return text;
}
return null;
}
}
static IEnumerable<BodyPartBasic> EnumerateBodyParts (BodyPart entity, bool attachmentsOnly)
{
if (entity == null)
yield break;
var multipart = entity as BodyPartMultipart;
if (multipart != null) {
foreach (var subpart in multipart.BodyParts) {
foreach (var part in EnumerateBodyParts (subpart, attachmentsOnly))
yield return part;
}
yield break;
}
var basic = (BodyPartBasic) entity;
if (attachmentsOnly && !basic.IsAttachment)
yield break;
yield return basic;
}
/// <summary>
/// Gets the body parts of the message.
/// </summary>
/// <remarks>
/// <para>Traverses over the <see cref="Body"/>, enumerating all of the
/// <see cref="BodyPartBasic"/> objects.</para>
/// <para>This property will only be usable if either the
/// <see cref="MessageSummaryItems.Body"/> flag or the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The body parts.</value>
public IEnumerable<BodyPartBasic> BodyParts {
get { return EnumerateBodyParts (Body, false); }
}
/// <summary>
/// Gets the attachments.
/// </summary>
/// <remarks>
/// <para>Traverses over the <see cref="Body"/>, enumerating all of the
/// <see cref="BodyPartBasic"/> objects that have a <c>Content-Disposition</c>
/// header set to <c>"attachment"</c>.</para>
/// <para>This property will only be usable if the
/// <see cref="MessageSummaryItems.BodyStructure"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
/// <value>The attachments.</value>
public IEnumerable<BodyPartBasic> Attachments {
get { return EnumerateBodyParts (Body, true); }
}
/// <summary>
/// Gets the preview text of the message.
/// </summary>
/// <remarks>
/// <para>The preview text is a short snippet of the beginning of the message
/// text, typically shown in a mail client's message list to provide the user
/// with a sense of what the message is about.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.PreviewText"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The preview text.</value>
public string PreviewText {
get; set;
}
/// <summary>
/// Gets the envelope of the message, if available.
/// </summary>
/// <remarks>
/// <para>The envelope of a message contains information such as the
/// date the message was sent, the subject of the message,
/// the sender of the message, who the message was sent to,
/// which message(s) the message may be in reply to,
/// and the message id.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Envelope"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The envelope of the message.</value>
public Envelope Envelope {
get; set;
}
/// <summary>
/// Gets the normalized subject.
/// </summary>
/// <remarks>
/// A normalized Subject header value where prefixes such as
/// "Re:", "Re[#]:", etc have been pruned.
/// </remarks>
/// <value>The normalized subject.</value>
public string NormalizedSubject {
get {
UpdateThreadableSubject ();
return normalizedSubject;
}
}
/// <summary>
/// Gets whether or not the message is a reply.
/// </summary>
/// <remarks>
/// This value should be based on whether the message subject contained any "Re:" or "Fwd:" prefixes.
/// </remarks>
/// <value><c>true</c> if the message is a reply; otherwise, <c>false</c>.</value>
public bool IsReply {
get {
UpdateThreadableSubject ();
return threadableReplyDepth != 0;
}
}
/// <summary>
/// Gets the Date header value.
/// </summary>
/// <remarks>
/// Gets the Date header value. If the Date header is not present, the arrival date is used.
/// If neither are known, <see cref="System.DateTimeOffset.MinValue"/> is returned.
/// </remarks>
/// <value>The date.</value>
public DateTimeOffset Date {
get { return Envelope?.Date ?? InternalDate ?? DateTimeOffset.MinValue; }
}
/// <summary>
/// Gets the message flags, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message flags, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Flags"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The message flags.</value>
public MessageFlags? Flags {
get; set;
}
/// <summary>
/// Gets the user-defined message flags, if available.
/// </summary>
/// <remarks>
/// <para>Gets the user-defined message flags, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Flags"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The user-defined message flags.</value>
public HashSet<string> Keywords {
get; set;
}
/// <summary>
/// Gets the user-defined message flags, if available.
/// </summary>
/// <remarks>
/// <para>Gets the user-defined message flags, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Flags"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The user-defined message flags.</value>
[Obsolete ("Use Keywords instead.")]
public HashSet<string> UserFlags {
get { return Keywords; }
set { Keywords = value; }
}
/// <summary>
/// Gets the message annotations, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message annotations, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Annotations"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The message annotations.</value>
public IList<Annotation> Annotations {
get; set;
}
/// <summary>
/// Gets the list of headers, if available.
/// </summary>
/// <remarks>
/// <para>Gets the list of headers, if available.</para>
/// <para>This property will only be set if <see cref="MessageSummaryItems.Headers"/>
/// is specified in a call to one of the
/// <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods or specific headers are requested via a one of the Fetch or FetchAsync methods
/// that accept list of specific headers to request for each message such as
/// <see cref="IMailFolder.Fetch(System.Collections.Generic.IList&lt;UniqueId&gt;,MessageSummaryItems,System.Collections.Generic.IEnumerable&lt;MimeKit.HeaderId&gt;,System.Threading.CancellationToken)"/>.
/// </para>
/// </remarks>
/// <value>The list of headers.</value>
public HeaderList Headers {
get; set;
}
/// <summary>
/// Gets the internal date of the message (i.e. the "received" date), if available.
/// </summary>
/// <remarks>
/// <para>Gets the internal date of the message (i.e. the "received" date), if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.InternalDate"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The internal date of the message.</value>
public DateTimeOffset? InternalDate {
get; set;
}
/// <summary>
/// Gets the size of the message, in bytes, if available.
/// </summary>
/// <remarks>
/// <para>Gets the size of the message, in bytes, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.Size"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The size of the message.</value>
public uint? Size {
get; set;
}
/// <summary>
/// Gets the mod-sequence value for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the mod-sequence value for the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.ModSeq"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The mod-sequence value.</value>
public ulong? ModSeq {
get; set;
}
/// <summary>
/// Gets the message-ids that the message references, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message-ids that the message references, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.References"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The references.</value>
public MessageIdList References {
get; set;
}
/// <summary>
/// Get the globally unique identifier for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the globally unique identifier of the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.EmailId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// <note type="info">This property maps to the <c>EMAILID</c> value defined in the
/// <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.</note>
/// </remarks>
/// <value>The globally unique message identifier.</value>
public string EmailId {
get; set;
}
/// <summary>
/// Get the globally unique identifier for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the globally unique identifier of the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.EmailId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// <note type="info">This property maps to the <c>EMAILID</c> value defined in the
/// <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.</note>
/// </remarks>
/// <value>The globally unique message identifier.</value>
[Obsolete ("Use EmailId instead.")]
public string Id {
get { return EmailId; }
}
/// <summary>
/// Get the globally unique thread identifier for the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the globally unique thread identifier for the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.ThreadId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// <note type="info">This property maps to the <c>THREADID</c> value defined in the
/// <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.</note>
/// </remarks>
/// <value>The globally unique thread identifier.</value>
public string ThreadId {
get; set;
}
/// <summary>
/// Gets the unique identifier of the message, if available.
/// </summary>
/// <remarks>
/// <para>Gets the unique identifier of the message, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.UniqueId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The uid of the message.</value>
public UniqueId UniqueId {
get; set;
}
/// <summary>
/// Gets the index of the message.
/// </summary>
/// <remarks>
/// <para>Gets the index of the message.</para>
/// <para>This property is always set.</para>
/// </remarks>
/// <value>The index of the message.</value>
public int Index {
get; internal set;
}
#region GMail extension properties
/// <summary>
/// Gets the GMail message identifier, if available.
/// </summary>
/// <remarks>
/// <para>Gets the GMail message identifier, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.GMailMessageId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The GMail message identifier.</value>
public ulong? GMailMessageId {
get; set;
}
/// <summary>
/// Gets the GMail thread identifier, if available.
/// </summary>
/// <remarks>
/// <para>Gets the GMail thread identifier, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.GMailThreadId"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The GMail thread identifier.</value>
public ulong? GMailThreadId {
get; set;
}
/// <summary>
/// Gets the list of GMail labels, if available.
/// </summary>
/// <remarks>
/// <para>Gets the list of GMail labels, if available.</para>
/// <para>This property will only be set if the
/// <see cref="MessageSummaryItems.GMailLabels"/> flag is passed to
/// one of the <a href="Overload_MailKit_IMailFolder_Fetch.htm">Fetch</a>
/// or <a href="Overload_MailKit_IMailFolder_FetchAsync.htm">FetchAsync</a>
/// methods.</para>
/// </remarks>
/// <value>The GMail labels.</value>
public IList<string> GMailLabels {
get; set;
}
#endregion
}
}

View File

@ -0,0 +1,67 @@
//
// MessageSummaryFetchedEventArgs.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;
namespace MailKit {
/// <summary>
/// Event args used when a message summary has been fetched from a folder.
/// </summary>
/// <remarks>
/// Event args used when a message summary has been fetched from a folder.
/// </remarks>
public class MessageSummaryFetchedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageSummaryFetchedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageSummaryFetchedEventArgs"/>
/// </remarks>
/// <param name="message">The message summary.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="message"/> is <c>null</c>.
/// </exception>
public MessageSummaryFetchedEventArgs (IMessageSummary message)
{
if (message == null)
throw new ArgumentNullException (nameof (message));
Message = message;
}
/// <summary>
/// Get the message summary.
/// </summary>
/// <remarks>
/// Gets the message summary.
/// </remarks>
/// <value>The message summary.</value>
public IMessageSummary Message {
get; private set;
}
}
}

View File

@ -0,0 +1,222 @@
//
// FetchFlags.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;
namespace MailKit {
/// <summary>
/// A bitfield of <see cref="MessageSummary"/> fields.
/// </summary>
/// <remarks>
/// <see cref="MessageSummaryItems"/> are used to specify which properties
/// of <see cref="MessageSummary"/> should be populated by calls to
/// <see cref="IMailFolder.Fetch(System.Collections.Generic.IList&lt;UniqueId&gt;, MessageSummaryItems, System.Threading.CancellationToken)"/>,
/// <see cref="IMailFolder.Fetch(System.Collections.Generic.IList&lt;int&gt;, MessageSummaryItems, System.Threading.CancellationToken)"/>, or
/// <see cref="IMailFolder.Fetch(int, int, MessageSummaryItems, System.Threading.CancellationToken)"/>.
/// </remarks>
[Flags]
public enum MessageSummaryItems {
/// <summary>
/// Don't fetch any summary items.
/// </summary>
None = 0,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.Annotations"/>.</para>
/// <para>Fetches all <c>ANNOATION</c> values as defined in
/// <a href="https://tools.ietf.org/html/rfc5257">rfc5257</a>.</para>
/// </summary>
Annotations = 1 << 0,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.Body"/>.</para>
/// <para>Fetches the <c>BODY</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// <note type="note">Unlike <see cref="BodyStructure"/>, <c>Body</c> will not populate the
/// <see cref="BodyPart.ContentType"/> parameters nor will it populate the
/// <see cref="BodyPartBasic.ContentDisposition"/>, <see cref="BodyPartBasic.ContentLanguage"/>
/// or <see cref="BodyPartBasic.ContentLocation"/> properties of each <see cref="BodyPartBasic"/>
/// body part. This makes <c>Body</c> far less useful than <c>BodyStructure</c> especially when
/// it is desirable to determine whether or not a body part is an attachment.</note>
/// </summary>
Body = 1 << 1,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.Body"/> (but with more details than <see cref="Body"/>).</para>
/// <para>Fetches the <c>BODYSTRUCTURE</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// <note type="note">Unlike <see cref="Body"/>, <c>BodyStructure</c> will also populate the
/// <see cref="BodyPart.ContentType"/> parameters as well as the
/// <see cref="BodyPartBasic.ContentDisposition"/>, <see cref="BodyPartBasic.ContentLanguage"/>
/// and <see cref="BodyPartBasic.ContentLocation"/> properties of each <see cref="BodyPartBasic"/>
/// body part. The <c>Content-Disposition</c> information is especially important when trying to
/// determine whether or not a body part is an attachment, for example.</note>
/// </summary>
BodyStructure = 1 << 2,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.Envelope"/>.</para>
/// <para>Fetches the <c>ENVELOPE</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
Envelope = 1 << 3,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.Flags"/>.</para>
/// <para>Fetches the <c>FLAGS</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
Flags = 1 << 4,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.InternalDate"/>.</para>
/// <para>Fetches the <c>INTERNALDATE</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
InternalDate = 1 << 5,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.Size"/>.</para>
/// <para>Fetches the <c>RFC822.SIZE</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
Size = 1 << 6,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.ModSeq"/>.</para>
/// <para>Fetches the <c>MODSEQ</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc4551">rfc4551</a>.</para>
/// </summary>
ModSeq = 1 << 7,
/// <summary>
/// Fetch the <see cref="IMessageSummary.References"/>.
/// </summary>
References = 1 << 8,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.UniqueId"/>.</para>
/// <para>Fetches the <c>UID</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
UniqueId = 1 << 9,
/// <summary>
/// <para></para>Fetch the <see cref="IMessageSummary.EmailId"/>.
/// <para>Fetches the <c>EMAILID</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc8474">rfc8474</a>.</para>
/// </summary>
EmailId = 1 << 10,
/// <summary>
/// <para></para>Fetch the <see cref="IMessageSummary.EmailId"/>.
/// <para>Fetches the <c>EMAILID</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc8474">rfc8474</a>.</para>
/// </summary>
[Obsolete ("Use EmailId instead.")]
Id = EmailId,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.ThreadId"/>.</para>
/// <para>Fetches the <c>THREADID</c> value as defined in
/// <a href="https://tools.ietf.org/html/rfc8474">rfc8474</a>.</para>
/// </summary>
ThreadId = 1 << 11,
#region GMail extension items
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.GMailMessageId"/>.</para>
/// <para>Fetches the <c>X-GM-MSGID</c> value as defined in Google's
/// <a href="https://developers.google.com/gmail/imap/imap-extensions">IMAP extensions</a>
/// documentation.</para>
/// </summary>
GMailMessageId = 1 << 12,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.GMailThreadId"/>.</para>
/// <para>Fetches the <c>X-GM-THRID</c> value as defined in Google's
/// <a href="https://developers.google.com/gmail/imap/imap-extensions">IMAP extensions</a>
/// documentation.</para>
/// </summary>
GMailThreadId = 1 << 13,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.GMailLabels"/>.</para>
/// <para>Fetches the <c>X-GM-LABELS</c> value as defined in Google's
/// <a href="https://developers.google.com/gmail/imap/imap-extensions">IMAP extensions</a>
/// documentation.</para>
/// </summary>
GMailLabels = 1 << 14,
#endregion
/// <summary>
/// <para>Fetch the the complete list of <see cref="IMessageSummary.Headers"/> for each message.</para>
/// </summary>
Headers = 1 << 15,
/// <summary>
/// <para>Fetch the <see cref="IMessageSummary.PreviewText"/>.</para>
/// <note type="note">This property is quite expensive to calculate because it is not an
/// item that is cached on the IMAP server. Instead, MailKit must download a hunk of the
/// message body so that it can decode and parse it in order to generate a meaningful
/// text snippet. This usually involves downloading the first 512 bytes for <c>text/plain</c>
/// message bodies and the first 16 kilobytes for <c>text/html</c> message bodies. If a
/// message contains both a <c>text/plain</c> body and a <c>text/html</c> body, then the
/// <c>text/plain</c> content is used in order to reduce network traffic.</note>
/// </summary>
PreviewText = 1 << 16,
#region Macros
/// <summary>
/// <para>A macro for fetching the <see cref="Envelope"/>, <see cref="Flags"/>,
/// <see cref="InternalDate"/>, and <see cref="Size"/> values.</para>
/// <para>This macro maps to the equivalent <c>ALL</c> macro as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
All = Envelope | Flags | InternalDate | Size,
/// <summary>
/// <para>A macro for fetching the <see cref="Flags"/>, <see cref="InternalDate"/>, and
/// <see cref="Size"/> values.</para>
/// <para>This macro maps to the equivalent <c>FAST</c> macro as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
Fast = Flags | InternalDate | Size,
/// <summary>
/// <para>A macro for fetching the <see cref="Body"/>, <see cref="Envelope"/>,
/// <see cref="Flags"/>, <see cref="InternalDate"/>, and <see cref="Size"/> values.</para>
/// <para>This macro maps to the equivalent <c>FULL</c> macro as defined in
/// <a href="https://tools.ietf.org/html/rfc3501">rfc3501</a>.</para>
/// </summary>
Full = Body | Envelope | Flags| InternalDate | Size,
#endregion
}
}

View File

@ -0,0 +1,108 @@
//
// MessageThread.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.Collections.Generic;
namespace MailKit {
/// <summary>
/// A message thread.
/// </summary>
/// <remarks>
/// A message thread.
/// </remarks>
public class MessageThread
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageThread"/> class.
/// </summary>
/// <remarks>
/// Creates a new message thread node.
/// </remarks>
/// <param name="uid">The unique identifier of the message.</param>
public MessageThread (UniqueId? uid)
{
Children = new List<MessageThread> ();
UniqueId = uid;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageThread"/> class.
/// </summary>
/// <remarks>
/// Creates a new message thread node.
/// </remarks>
/// <param name="message">The message summary.</param>
public MessageThread (IMessageSummary message)
{
Children = new List<MessageThread> ();
if (message != null && message.UniqueId.IsValid)
UniqueId = message?.UniqueId;
Message = message;
}
/// <summary>
/// Gets the message summary, if available.
/// </summary>
/// <remarks>
/// <para>Gets the message summary, if available.</para>
/// <note type="note">This property will only ever be set if the <see cref="MessageThread"/>
/// was created by the <see cref="MessageThreader"/>. <see cref="MessageThread"/>s that are
/// created by any of the
/// <a href="Overload_MailKit_Net_Imap_ImapFolder_Thread.htm">Thread</a> or
/// <a href="Overload_MailKit_Net_Imap_ImapFolder_ThreadAsync.htm">ThreadAsync</a>
/// methods will always be <c>null</c>.</note>
/// </remarks>
/// <value>The message summary.</value>
public IMessageSummary Message {
get; private set;
}
/// <summary>
/// Gets the unique identifier of the message.
/// </summary>
/// <remarks>
/// The unique identifier may be <c>null</c> if the message is missing from the
/// <see cref="IMailFolder"/> or from the list of messages provided to the
/// <see cref="MessageThreader"/>.
/// </remarks>
/// <value>The unique identifier.</value>
public UniqueId? UniqueId {
// FIXME: this shouldn't be a nullable since we can just use UniqueId.Invalid
get; private set;
}
/// <summary>
/// Gets the children.
/// </summary>
/// <remarks>
/// Each child represents a reply to the message referenced by <see cref="UniqueId"/>.
/// </remarks>
/// <value>The children.</value>
public IList<MessageThread> Children {
get; private set;
}
}
}

View File

@ -0,0 +1,603 @@
//
// MessageThreader.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.Text;
using System.Collections.Generic;
using MimeKit;
using MimeKit.Utils;
using MailKit.Search;
namespace MailKit {
/// <summary>
/// Threads messages according to the algorithms defined in rfc5256.
/// </summary>
/// <remarks>
/// Threads messages according to the algorithms defined in rfc5256.
/// </remarks>
public static class MessageThreader
{
internal class ThreadableNode : IMessageSummary
{
public readonly List<ThreadableNode> Children = new List<ThreadableNode> ();
public IMessageSummary Message;
public ThreadableNode Parent;
public ThreadableNode (IMessageSummary message)
{
Message = message;
}
public bool HasParent {
get { return Parent != null; }
}
public bool HasChildren {
get { return Children.Count > 0; }
}
public IMailFolder Folder => null;
public MessageSummaryItems Fields {
get { return MessageSummaryItems.UniqueId | MessageSummaryItems.Envelope | MessageSummaryItems.ModSeq | MessageSummaryItems.Size; }
}
public BodyPart Body => null;
public BodyPartText TextBody => null;
public BodyPartText HtmlBody => null;
public IEnumerable<BodyPartBasic> BodyParts => null;
public IEnumerable<BodyPartBasic> Attachments => null;
public string PreviewText => null;
public Envelope Envelope {
get { return Message != null ? Message.Envelope : Children[0].Envelope; }
}
public string NormalizedSubject {
get { return Message != null ? Message.NormalizedSubject : Children[0].NormalizedSubject; }
}
public DateTimeOffset Date {
get { return Message != null ? Message.Date : Children[0].Date; }
}
public bool IsReply {
get { return Message != null && Message.IsReply; }
}
public MessageFlags? Flags => null;
public HashSet<string> Keywords => null;
[Obsolete]
public HashSet<string> UserFlags => null;
public IList<Annotation> Annotations {
get { return Message != null ? Message.Annotations : Children[0].Annotations; }
}
public HeaderList Headers => null;
public DateTimeOffset? InternalDate => null;
public uint? Size {
get { return Message != null ? Message.Size : Children[0].Size; }
}
public ulong? ModSeq {
get { return Message != null ? Message.ModSeq : Children[0].ModSeq; }
}
public MessageIdList References {
get { return Message != null ? Message.References : Children[0].References; }
}
public string EmailId => null;
[Obsolete]
public string Id => null;
public string ThreadId => null;
public UniqueId UniqueId {
get { return Message != null ? Message.UniqueId : Children[0].UniqueId; }
}
public int Index {
get { return Message != null ? Message.Index : Children[0].Index; }
}
public ulong? GMailMessageId => null;
public ulong? GMailThreadId => null;
public IList<string> GMailLabels => null;
}
static IDictionary<string, ThreadableNode> CreateIdTable (IEnumerable<IMessageSummary> messages)
{
var ids = new Dictionary<string, ThreadableNode> (StringComparer.OrdinalIgnoreCase);
ThreadableNode node;
foreach (var message in messages) {
if (message.Envelope == null)
throw new ArgumentException ("One or more messages is missing information needed for threading.", nameof (messages));
var id = message.Envelope.MessageId;
if (string.IsNullOrEmpty (id))
id = MimeUtils.GenerateMessageId ();
if (ids.TryGetValue (id, out node)) {
if (node.Message == null) {
// a previously processed message referenced this message
node.Message = message;
} else {
// a duplicate message-id, just create a dummy id and use that
id = MimeUtils.GenerateMessageId ();
node = null;
}
}
if (node == null) {
// create a new ThreadContainer for this message and add it to ids
node = new ThreadableNode (message);
ids.Add (id, node);
}
ThreadableNode parent = null;
foreach (var reference in message.References) {
ThreadableNode referenced;
if (!ids.TryGetValue (reference, out referenced)) {
// create a dummy container for the referenced message
referenced = new ThreadableNode (null);
ids.Add (reference, referenced);
}
// chain up the references, disallowing loops
if (parent != null && referenced.Parent == null && parent != referenced && !parent.Children.Contains (referenced)) {
parent.Children.Add (referenced);
referenced.Parent = parent;
}
parent = referenced;
}
// don't allow loops
if (parent != null && (parent == node || node.Children.Contains (parent)))
parent = null;
if (node.HasParent) {
// unlink from our old parent
node.Parent.Children.Remove (node);
node.Parent = null;
}
if (parent != null) {
// add it as a child of our new parent
parent.Children.Add (node);
node.Parent = parent;
}
}
return ids;
}
static ThreadableNode CreateRoot (IDictionary<string, ThreadableNode> ids)
{
var root = new ThreadableNode (null);
foreach (var message in ids.Values) {
if (message.Parent == null)
root.Children.Add (message);
}
return root;
}
static void PruneEmptyContainers (ThreadableNode root)
{
for (int i = 0; i < root.Children.Count; i++) {
var node = root.Children[i];
if (node.Message == null && node.Children.Count == 0) {
// this is an empty container with no children, nuke it.
root.Children.RemoveAt (i);
i--;
} else if (node.Message == null && node.HasChildren && (node.HasParent || node.Children.Count == 1)) {
// If the Container has no Message, but does have children, remove this container but promote
// its children to this level (that is, splice them in to the current child list.)
//
// Do not promote the children if doing so would promote them to the root set -- unless there
// is only one child, in which case, do.
root.Children.RemoveAt (i);
for (int j = 0; j < node.Children.Count; j++) {
node.Children[j].Parent = node.Parent;
root.Children.Add (node.Children[j]);
}
node.Children.Clear ();
i--;
} else if (node.HasChildren) {
PruneEmptyContainers (node);
}
}
}
static void GroupBySubject (ThreadableNode root)
{
var subjects = new Dictionary<string, ThreadableNode> (StringComparer.OrdinalIgnoreCase);
ThreadableNode match;
int count = 0;
for (int i = 0; i < root.Children.Count; i++) {
var current = root.Children[i];
var subject = current.NormalizedSubject;
// don't thread messages with empty subjects
if (string.IsNullOrEmpty (subject))
continue;
if (!subjects.TryGetValue (subject, out match) ||
(current.Message == null && match.Message != null) ||
(match.Message != null && match.Message.IsReply &&
current.Message != null && !current.Message.IsReply)) {
subjects[subject] = current;
count++;
}
}
if (count == 0)
return;
for (int i = 0; i < root.Children.Count; i++) {
var current = root.Children[i];
var subject = current.NormalizedSubject;
// don't thread messages with empty subjects
if (string.IsNullOrEmpty (subject))
continue;
match = subjects[subject];
if (match == current)
continue;
// remove the second message with the same subject
root.Children.RemoveAt (i--);
// group these messages together...
if (match.Message == null && current.Message == null) {
// If both messages are dummies, append the current message's children
// to the children of the message in the subject table (the children of
// both messages become siblings), and then delete the current message.
match.Children.AddRange (current.Children);
} else if (match.Message == null && current.Message != null) {
// If the message in the subject table is a dummy and the current message
// is not, make the current message a child of the message in the subject
// table (a sibling of its children).
match.Children.Add (current);
} else if (current.Message.IsReply && !match.Message.IsReply) {
// If the current message is a reply or forward and the message in the
// subject table is not, make the current message a child of the message
// in the subject table (a sibling of its children).
match.Children.Add (current);
} else {
// Otherwise, create a new dummy message and make both the current message
// and the message in the subject table children of the dummy. Then replace
// the message in the subject table with the dummy message.
// Note: if we re-use the node already in the subject table and the root, then
// we won't have to insert the new dummy node at the matched node's location
var dummy = match;
// clone the message already in the subject table
match = new ThreadableNode (dummy.Message);
match.Children.AddRange (dummy.Children);
// empty out the old match node (aka the new dummy node)
dummy.Children.Clear ();
dummy.Message = null;
// now add both messages to the dummy
dummy.Children.Add (match);
dummy.Children.Add (current);
}
}
}
static void GetThreads (ThreadableNode root, IList<MessageThread> threads, IList<OrderBy> orderBy)
{
root.Children.Sort (orderBy);
for (int i = 0; i < root.Children.Count; i++) {
var message = root.Children[i].Message;
var thread = new MessageThread (message);
GetThreads (root.Children[i], thread.Children, orderBy);
threads.Add (thread);
}
}
static IList<MessageThread> ThreadByReferences (IEnumerable<IMessageSummary> messages, IList<OrderBy> orderBy)
{
var threads = new List<MessageThread> ();
var ids = CreateIdTable (messages);
var root = CreateRoot (ids);
PruneEmptyContainers (root);
GroupBySubject (root);
GetThreads (root, threads, orderBy);
return threads;
}
static IList<MessageThread> ThreadBySubject (IEnumerable<IMessageSummary> messages, IList<OrderBy> orderBy)
{
var threads = new List<MessageThread> ();
var root = new ThreadableNode (null);
foreach (var message in messages) {
if (message.Envelope == null)
throw new ArgumentException ("One or more messages is missing information needed for threading.", nameof (messages));
var node = new ThreadableNode (message);
root.Children.Add (node);
}
GroupBySubject (root);
GetThreads (root, threads, orderBy);
return threads;
}
/// <summary>
/// Thread the messages according to the specified threading algorithm.
/// </summary>
/// <remarks>
/// Thread the messages according to the specified threading algorithm.
/// </remarks>
/// <returns>The threaded messages.</returns>
/// <param name="messages">The messages.</param>
/// <param name="algorithm">The threading algorithm.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="messages"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="algorithm"/> is not a valid threading algorithm.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="messages"/> contains one or more items that is missing information needed for threading.
/// </exception>
public static IList<MessageThread> Thread (this IEnumerable<IMessageSummary> messages, ThreadingAlgorithm algorithm)
{
return Thread (messages, algorithm, new [] { OrderBy.Arrival });
}
/// <summary>
/// Threads the messages according to the specified threading algorithm
/// and sorts the resulting threads by the specified ordering.
/// </summary>
/// <remarks>
/// Threads the messages according to the specified threading algorithm
/// and sorts the resulting threads by the specified ordering.
/// </remarks>
/// <returns>The threaded messages.</returns>
/// <param name="messages">The messages.</param>
/// <param name="algorithm">The threading algorithm.</param>
/// <param name="orderBy">The requested sort ordering.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="messages"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="orderBy"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="algorithm"/> is not a valid threading algorithm.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para><paramref name="messages"/> contains one or more items that is missing information needed for threading or sorting.</para>
/// <para>-or-</para>
/// <para><paramref name="orderBy"/> is an empty list.</para>
/// </exception>
public static IList<MessageThread> Thread (this IEnumerable<IMessageSummary> messages, ThreadingAlgorithm algorithm, IList<OrderBy> orderBy)
{
if (messages == null)
throw new ArgumentNullException (nameof (messages));
if (orderBy == null)
throw new ArgumentNullException (nameof (orderBy));
if (orderBy.Count == 0)
throw new ArgumentException ("No sort order provided.", nameof (orderBy));
switch (algorithm) {
case ThreadingAlgorithm.OrderedSubject: return ThreadBySubject (messages, orderBy);
case ThreadingAlgorithm.References: return ThreadByReferences (messages, orderBy);
default: throw new ArgumentOutOfRangeException (nameof (algorithm));
}
}
static bool IsForward (string subject, int index)
{
return (subject[index] == 'F' || subject[index] == 'f') &&
(subject[index + 1] == 'W' || subject[index + 1] == 'w') &&
(subject[index + 2] == 'D' || subject[index + 2] == 'd') &&
subject[index + 3] == ':';
}
static bool IsReply (string subject, int index)
{
return (subject[index] == 'R' || subject[index] == 'r') &&
(subject[index + 1] == 'E' || subject[index + 1] == 'e');
}
static void SkipWhiteSpace (string subject, ref int index)
{
while (index < subject.Length && char.IsWhiteSpace (subject[index]))
index++;
}
static bool IsMailingListName (char c)
{
return c == '-' || c == '_' || char.IsLetterOrDigit (c);
}
static void SkipMailingListName (string subject, ref int index)
{
while (index < subject.Length && IsMailingListName (subject[index]))
index++;
}
static bool SkipDigits (string subject, ref int index, out int value)
{
int startIndex = index;
value = 0;
while (index < subject.Length && char.IsDigit (subject[index])) {
value = (value * 10) + (subject[index] - '0');
index++;
}
return index > startIndex;
}
/// <summary>
/// Gets the threadable subject.
/// </summary>
/// <remarks>
/// Gets the threadable subject.
/// </remarks>
/// <returns>The threadable subject.</returns>
/// <param name="subject">The Subject header value.</param>
/// <param name="replyDepth">The reply depth.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="subject"/> is <c>null</c>.
/// </exception>
public static string GetThreadableSubject (string subject, out int replyDepth)
{
if (subject == null)
throw new ArgumentNullException (nameof (subject));
replyDepth = 0;
int endIndex = subject.Length;
int startIndex = 0;
int index, count;
int left;
do {
SkipWhiteSpace (subject, ref startIndex);
index = startIndex;
if ((left = (endIndex - index)) < 3)
break;
if (left >= 4 && IsForward (subject, index)) {
// skip over the "Fwd:" prefix
startIndex = index + 4;
replyDepth++;
continue;
}
if (IsReply (subject, index)) {
if (subject[index + 2] == ':') {
// skip over the "Re:" prefix
startIndex = index + 3;
replyDepth++;
continue;
}
if (subject[index + 2] == '[' || subject[index + 2] == '(') {
char close = subject[index + 2] == '[' ? ']' : ')';
// skip over "Re[" or "Re("
index += 3;
// if this is followed by "###]:" or "###):", then it's a condensed "Re:"
if (SkipDigits (subject, ref index, out count) && (endIndex - index) >= 2 &&
subject[index] == close && subject[index + 1] == ':') {
startIndex = index + 2;
replyDepth += count;
continue;
}
}
} else if (subject[index] == '[' && char.IsLetterOrDigit (subject[index + 1])) {
// possibly a mailing-list prefix
index += 2;
SkipMailingListName (subject, ref index);
if ((endIndex - index) >= 1 && subject[index] == ']') {
startIndex = index + 1;
continue;
}
}
break;
} while (true);
// trim trailing whitespace
while (endIndex > 0 && char.IsWhiteSpace (subject[endIndex - 1]))
endIndex--;
// canonicalize the remainder of the subject, condensing multiple spaces into 1
var builder = new StringBuilder ();
bool lwsp = false;
for (int i = startIndex; i < endIndex; i++) {
if (char.IsWhiteSpace (subject[i])) {
if (!lwsp) {
builder.Append (' ');
lwsp = true;
}
} else {
builder.Append (subject[i]);
lwsp = false;
}
}
var canonicalized = builder.ToString ();
if (canonicalized.Equals ("(no subject)", StringComparison.OrdinalIgnoreCase))
canonicalized = string.Empty;
return canonicalized;
}
}
}

View File

@ -0,0 +1,79 @@
//
// MessagesVanishedEventArgs.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.Collections.Generic;
using System.Collections.ObjectModel;
namespace MailKit {
/// <summary>
/// Event args used when a message vanishes from a folder.
/// </summary>
/// <remarks>
/// Event args used when a message vanishes from a folder.
/// </remarks>
public class MessagesVanishedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessagesVanishedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessagesVanishedEventArgs"/>.
/// </remarks>
/// <param name="uids">The list of unique identifiers.</param>
/// <param name="earlier">If set to <c>true</c>, the messages vanished in the past as opposed to just now.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="uids"/> is <c>null</c>.
/// </exception>
public MessagesVanishedEventArgs (IList<UniqueId> uids, bool earlier)
{
UniqueIds = new ReadOnlyCollection<UniqueId> (uids);
Earlier = earlier;
}
/// <summary>
/// Gets the unique identifiers of the messages that vanished.
/// </summary>
/// <remarks>
/// Gets the unique identifiers of the messages that vanished.
/// </remarks>
/// <value>The unique identifiers.</value>
public IList<UniqueId> UniqueIds {
get; private set;
}
/// <summary>
/// Gets whether the messages vanished in the past as opposed to just now.
/// </summary>
/// <remarks>
/// Gets whether the messages vanished in the past as opposed to just now.
/// </remarks>
/// <value><c>true</c> if the messages vanished earlier; otherwise, <c>false</c>.</value>
public bool Earlier {
get; private set;
}
}
}

74
src/MailKit/Metadata.cs Normal file
View File

@ -0,0 +1,74 @@
//
// Metadata.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.
//
namespace MailKit {
/// <summary>
/// A metadata tag and value.
/// </summary>
/// <remarks>
/// A metadata tag and value.
/// </remarks>
public class Metadata
{
internal string EncodedName;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Metadata"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="Metadata"/>.
/// </remarks>
/// <param name="tag">The metadata tag.</param>
/// <param name="value">The metadata value.</param>
public Metadata (MetadataTag tag, string value)
{
Value = value;
Tag = tag;
}
/// <summary>
/// Gets the metadata tag.
/// </summary>
/// <remarks>
/// Gets the metadata tag.
/// </remarks>
/// <value>The metadata tag.</value>
public MetadataTag Tag {
get; private set;
}
/// <summary>
/// Gets the metadata value.
/// </summary>
/// <remarks>
/// Gets the metadata value.
/// </remarks>
/// <value>The metadata value.</value>
public string Value {
get; private set;
}
}
}

View File

@ -0,0 +1,67 @@
//
// MetadataChangedEventArgs.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;
namespace MailKit {
/// <summary>
/// Event args used when a metadata changes.
/// </summary>
/// <remarks>
/// Event args used when a metadata changes.
/// </remarks>
public class MetadataChangedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.MetadataChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MetadataChangedEventArgs"/>.
/// </remarks>
/// <param name="metadata">The metadata that changed.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="metadata"/> is <c>null</c>.
/// </exception>
public MetadataChangedEventArgs (Metadata metadata)
{
if (metadata == null)
throw new ArgumentNullException (nameof (metadata));
Metadata = metadata;
}
/// <summary>
/// Get the metadata that changed.
/// </summary>
/// <remarks>
/// Gets the metadata that changed.
/// </remarks>
/// <value>The metadata.</value>
public Metadata Metadata {
get; private set;
}
}
}

View File

@ -0,0 +1,59 @@
//
// MetadataCollection.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.Collections.Generic;
namespace MailKit {
/// <summary>
/// A collection of metadata.
/// </summary>
/// <remarks>
/// A collection of metadata.
/// </remarks>
public class MetadataCollection : List<Metadata>
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MetadataCollection"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MetadataCollection"/>
/// </remarks>
public MetadataCollection ()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MetadataCollection"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MetadataCollection"/>.
/// </remarks>
/// <param name="collection">A collection of metadata.</param>
public MetadataCollection (IEnumerable<Metadata> collection) : base (collection)
{
}
}
}

View File

@ -0,0 +1,108 @@
//
// MetadataOptions.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;
namespace MailKit
{
/// <summary>
/// A set of options to use when requesting metadata.
/// </summary>
/// <remarks>
/// A set of options to use when requesting metadata.
/// </remarks>
public class MetadataOptions
{
int depth;
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.MetadataOptions"/> class.
/// </summary>
/// <remarks>
/// Creates a new set of options to use when requesting metadata.
/// </remarks>
public MetadataOptions ()
{
}
/// <summary>
/// Get or set the depth.
/// </summary>
/// <remarks>
/// <para>When the <see cref="Depth"/> option is specified, it extends the list of metadata tag
/// values returned by the GetMetadata() call. For each <see cref="MetadataTag"/> specified in the
/// the GetMetadata() call, the method returns the value of the specified metadata tag (if it exists),
/// plus all metadata tags below the specified entry up to the specified depth.</para>
/// <para>Three values are allowed for <see cref="Depth"/>:</para>
/// <para><c>0</c> - no entries below the specified metadata tag are returned.</para>
/// <para><c>1</c> - only entries immediately below the specified metadata tag are returned.</para>
/// <para><see cref="System.Int32.MaxValue"/> - all entries below the specified metadata tag are returned.</para>
/// <para>Thus, a depth of <c>1</c> for a tag entry of <c>"/a"</c> will match <c>"/a"</c> as well as its children
/// entries (e.g., <c>"/a/b"</c>), but will not match grandchildren entries (e.g., <c>"/a/b/c"</c>).</para>
/// <para>If the Depth option is not specified, this is the same as specifying <c>0</c>.</para>
/// </remarks>
/// <value>The depth.</value>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="value"/> is out of range.
/// </exception>
public int Depth {
get { return depth; }
set {
if (!(value == 0 || value == 1 || value == int.MaxValue))
throw new ArgumentOutOfRangeException (nameof (value));
depth = value;
}
}
/// <summary>
/// Get or set the max size of the metadata tags to request.
/// </summary>
/// <remarks>
/// When specified, the <see cref="MaxSize"/> property is used to filter the metadata tags
/// returned by the GetMetadata() call to only those with a value shorter than the max size
/// specified.
/// </remarks>
/// <value>The size of the max.</value>
public uint? MaxSize {
get; set;
}
/// <summary>
/// Get the length of the longest metadata value.
/// </summary>
/// <remarks>
/// If the <see cref="MaxSize"/> property is specified, once the GetMetadata() call returns,
/// the <see cref="LongEntries"/> property will be set to the length of the longest metadata
/// value that exceeded the <see cref="MaxSize"/> limit, otherwise a value of <c>0</c> will
/// be set.
/// </remarks>
/// <value>The length of the longest metadata value that exceeded the max size.</value>
public uint LongEntries {
get; set;
}
}
}

156
src/MailKit/MetadataTag.cs Normal file
View File

@ -0,0 +1,156 @@
//
// MetadataTag.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;
namespace MailKit {
/// <summary>
/// A metadata tag.
/// </summary>
/// <remarks>
/// A metadata tag.
/// </remarks>
public struct MetadataTag
{
/// <summary>
/// A metadata tag for specifying the contact information for the server administrator.
/// </summary>
/// <remarks>
/// Used to get the contact information of the administrator on a
/// <see cref="IMailStore"/>.
/// </remarks>
public static readonly MetadataTag SharedAdmin = new MetadataTag ("/shared/admin");
/// <summary>
/// A metadata tag for private comments.
/// </summary>
/// <remarks>
/// Used to get or set a private comment on a <see cref="IMailFolder"/>.
/// </remarks>
public static readonly MetadataTag PrivateComment = new MetadataTag ("/private/comment");
/// <summary>
/// A metadata tag for shared comments.
/// </summary>
/// <remarks>
/// Used to get or set a shared comment on a <see cref="IMailStore"/>
/// or <see cref="IMailFolder"/>.
/// </remarks>
public static readonly MetadataTag SharedComment = new MetadataTag ("/shared/comment");
/// <summary>
/// A metadata tag for specifying the special use of a folder.
/// </summary>
/// <remarks>
/// Used to get or set the special use of a <see cref="IMailFolder"/>.
/// </remarks>
public static readonly MetadataTag PrivateSpecialUse = new MetadataTag ("/private/specialuse");
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MetadataTag"/> struct.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MetadataTag"/>.
/// </remarks>
/// <param name="id">The metadata tag identifier.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="id"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="id"/> is an empty string.
/// </exception>
public MetadataTag (string id)
{
if (id == null)
throw new ArgumentNullException (nameof (id));
if (id.Length == 0)
throw new ArgumentException ("A metadata tag identifier cannot be empty.");
Id = id;
}
/// <summary>
/// Get the metadata tag identifier.
/// </summary>
/// <remarks>
/// Gets the metadata tag identifier.
/// </remarks>
/// <value>The metadata tag identifier.</value>
public string Id {
get; private set;
}
/// <summary>
/// Determine whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.MetadataTag"/>.
/// </summary>
/// <remarks>
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="MailKit.MetadataTag"/>.
/// </remarks>
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="MailKit.MetadataTag"/>.</param>
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
/// <see cref="MailKit.MetadataTag"/>; otherwise, <c>false</c>.</returns>
public override bool Equals (object obj)
{
return obj is MetadataTag && ((MetadataTag) obj).Id == Id;
}
/// <summary>
/// Serves as a hash function for a <see cref="MailKit.MetadataTag"/> object.
/// </summary>
/// <remarks>
/// Serves as a hash function for a <see cref="MailKit.MetadataTag"/> object.
/// </remarks>
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a hash table.</returns>
public override int GetHashCode ()
{
return Id.GetHashCode ();
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.MetadataTag"/>.
/// </summary>
/// <remarks>
/// Returns a <see cref="System.String"/> that represents the current <see cref="MailKit.MetadataTag"/>.
/// </remarks>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="MailKit.MetadataTag"/>.</returns>
public override string ToString ()
{
return Id;
}
internal static MetadataTag Create (string id)
{
switch (id) {
case "/shared/admin": return SharedAdmin;
case "/private/comment": return PrivateComment;
case "/shared/comment": return SharedComment;
case "/private/specialuse": return PrivateSpecialUse;
default: return new MetadataTag (id);
}
}
}
}

View File

@ -0,0 +1,86 @@
//
// ModSeqChangedEventArgs.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.
//
namespace MailKit
{
/// <summary>
/// Event args for the <see cref="IMailFolder.ModSeqChanged"/> event.
/// </summary>
/// <remarks>
/// Event args for the <see cref="IMailFolder.ModSeqChanged"/> event.
/// </remarks>
public class ModSeqChangedEventArgs : MessageEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.ModSeqChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ModSeqChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
internal ModSeqChangedEventArgs (int index) : base (index)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.MessageFlagsChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MessageFlagsChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="modseq">The modification sequence value.</param>
public ModSeqChangedEventArgs (int index, ulong modseq) : base (index)
{
ModSeq = modseq;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.ModSeqChangedEventArgs"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ModSeqChangedEventArgs"/>.
/// </remarks>
/// <param name="index">The message index.</param>
/// <param name="uid">The unique id of the message.</param>
/// <param name="modseq">The modification sequence value.</param>
public ModSeqChangedEventArgs (int index, UniqueId uid, ulong modseq) : base (index, uid)
{
ModSeq = modseq;
}
/// <summary>
/// Gets the updated mod-sequence value of the message.
/// </summary>
/// <remarks>
/// Gets the updated mod-sequence value of the message.
/// </remarks>
/// <value>The mod-sequence value.</value>
public ulong ModSeq {
get; internal set;
}
}
}

View File

@ -0,0 +1,965 @@
//
// AsyncImapClient.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.Net;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Collections.Generic;
using MailKit.Security;
namespace MailKit.Net.Imap
{
public partial class ImapClient
{
/// <summary>
/// Asynchronously enable compression over the IMAP connection.
/// </summary>
/// <remarks>
/// <para>Asynchronously enables compression over the IMAP connection.</para>
/// <para>If the IMAP server supports the <see cref="ImapCapabilities.Compress"/> extension,
/// it is possible at any point after connecting to enable compression to reduce network
/// bandwidth usage. Ideally, this method should be called before authenticating.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// Compression must be enabled before a folder has been selected.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the COMPRESS extension.
/// </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="ImapCommandException">
/// The server replied to the COMPRESS command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public Task CompressAsync (CancellationToken cancellationToken = default (CancellationToken))
{
return CompressAsync (true, cancellationToken);
}
/// <summary>
/// Asynchronously enable the QRESYNC feature.
/// </summary>
/// <remarks>
/// <para>Enables the <a href="https://tools.ietf.org/html/rfc5162">QRESYNC</a> feature.</para>
/// <para>The QRESYNC extension improves resynchronization performance of folders by
/// querying the IMAP server for a list of changes when the folder is opened using the
/// <see cref="ImapFolder.Open(FolderAccess,uint,ulong,System.Collections.Generic.IList&lt;UniqueId&gt;,System.Threading.CancellationToken)"/>
/// method.</para>
/// <para>If this feature is enabled, the <see cref="MailFolder.MessageExpunged"/> event is replaced
/// with the <see cref="MailFolder.MessagesVanished"/> event.</para>
/// <para>This method needs to be called immediately after calling one of the
/// <a href="Overload_MailKit_Net_Imap_ImapClient_Authenticate.htm">Authenticate</a> methods, before
/// opening any folders.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// Quick resynchronization needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the QRESYNC extension.
/// </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="ImapCommandException">
/// The server replied to the ENABLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public override Task EnableQuickResyncAsync (CancellationToken cancellationToken = default (CancellationToken))
{
return EnableQuickResyncAsync (true, cancellationToken);
}
/// <summary>
/// Asynchronously enable the UTF8=ACCEPT extension.
/// </summary>
/// <remarks>
/// Enables the <a href="https://tools.ietf.org/html/rfc6855">UTF8=ACCEPT</a> extension.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// UTF8=ACCEPT needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the UTF8=ACCEPT extension.
/// </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="ImapCommandException">
/// The server replied to the ENABLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public Task EnableUTF8Async (CancellationToken cancellationToken = default (CancellationToken))
{
return EnableUTF8Async (true, cancellationToken);
}
/// <summary>
/// Asynchronously identify the client implementation to the server and obtain the server implementation details.
/// </summary>
/// <remarks>
/// <para>Passes along the client implementation details to the server while also obtaining implementation
/// details from the server.</para>
/// <para>If the <paramref name="clientImplementation"/> is <c>null</c> or no properties have been set, no
/// identifying information will be sent to the server.</para>
/// <note type="security">
/// <para>Security Implications</para>
/// <para>This command has the danger of violating the privacy of users if misused. Clients should
/// notify users that they send the ID command.</para>
/// <para>It is highly desirable that implementations provide a method of disabling ID support, perhaps by
/// not calling this method at all, or by passing <c>null</c> as the <paramref name="clientImplementation"/>
/// argument.</para>
/// <para>Implementors must exercise extreme care in adding properties to the <paramref name="clientImplementation"/>.
/// Some properties, such as a processor ID number, Ethernet address, or other unique (or mostly unique) identifier
/// would allow tracking of users in ways that violate user privacy expectations and may also make it easier for
/// attackers to exploit security holes in the client.</para>
/// </note>
/// </remarks>
/// <returns>The implementation details of the server if available; otherwise, <c>null</c>.</returns>
/// <param name="clientImplementation">The client implementation.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the ID extension.
/// </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="ImapCommandException">
/// The server replied to the ID command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public Task<ImapImplementation> IdentifyAsync (ImapImplementation clientImplementation, CancellationToken cancellationToken = default (CancellationToken))
{
return IdentifyAsync (clientImplementation, true, cancellationToken);
}
/// <summary>
/// Asynchronously authenticate using the specified SASL mechanism.
/// </summary>
/// <remarks>
/// <para>Authenticates using the specified SASL mechanism.</para>
/// <para>For a list of available SASL authentication mechanisms supported by the server,
/// check the <see cref="AuthenticationMechanisms"/> property after the service has been
/// connected.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="mechanism">The SASL mechanism.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="mechanism"/> 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="System.InvalidOperationException">
/// The <see cref="ImapClient"/> is already authenticated.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="MailKit.Security.AuthenticationException">
/// Authentication using the supplied credentials has failed.
/// </exception>
/// <exception cref="MailKit.Security.SaslException">
/// A SASL authentication error occurred.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// An IMAP command failed.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public override Task AuthenticateAsync (SaslMechanism mechanism, CancellationToken cancellationToken = default (CancellationToken))
{
return AuthenticateAsync (mechanism, true, cancellationToken);
}
/// <summary>
/// Asynchronously authenticate using the supplied credentials.
/// </summary>
/// <remarks>
/// <para>If the IMAP server supports one or more SASL authentication mechanisms,
/// then the SASL mechanisms that both the client and server support are tried
/// in order of greatest security to weakest security. Once a SASL
/// authentication mechanism is found that both client and server support,
/// the credentials are used to authenticate.</para>
/// <para>If the server does not support SASL or if no common SASL mechanisms
/// can be found, then LOGIN command is used as a fallback.</para>
/// <note type="tip">To prevent the usage of certain authentication mechanisms,
/// simply remove them from the <see cref="AuthenticationMechanisms"/> hash set
/// before calling this method.</note>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="encoding">The text encoding to use for the user's credentials.</param>
/// <param name="credentials">The user's credentials.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="encoding"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="credentials"/> is <c>null</c>.</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="System.InvalidOperationException">
/// The <see cref="ImapClient"/> is already authenticated.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="MailKit.Security.AuthenticationException">
/// Authentication using the supplied credentials has failed.
/// </exception>
/// <exception cref="MailKit.Security.SaslException">
/// A SASL authentication error occurred.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// An IMAP command failed.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public override Task AuthenticateAsync (Encoding encoding, ICredentials credentials, CancellationToken cancellationToken = default (CancellationToken))
{
return AuthenticateAsync (encoding, credentials, true, cancellationToken);
}
/// <summary>
/// Asynchronously establish a connection to the specified IMAP server.
/// </summary>
/// <remarks>
/// <para>Establishes a connection to the specified IMAP or IMAP/S server.</para>
/// <para>If the <paramref name="port"/> has a value of <c>0</c>, then the
/// <paramref name="options"/> parameter is used to determine the default port to
/// connect to. The default port used with <see cref="SecureSocketOptions.SslOnConnect"/>
/// is <c>993</c>. All other values will use a default port of <c>143</c>.</para>
/// <para>If the <paramref name="options"/> has a value of
/// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used
/// to determine the default security options. If the <paramref name="port"/> has a value
/// of <c>993</c>, then the default options used will be
/// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use
/// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para>
/// <para>Once a connection is established, properties such as
/// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be
/// populated.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadMessages"/>
/// </example>
/// <returns>An asynchronous task context.</returns>
/// <param name="host">The host name to connect to.</param>
/// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param>
/// <param name="options">The secure socket options to when connecting.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="host"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// The <paramref name="host"/> is a zero-length string.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="ImapClient"/> has been disposed.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// The <see cref="ImapClient"/> is already connected.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <paramref name="options"/> was set to
/// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/>
/// and the IMAP server does not support the STARTTLS extension.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.Net.Sockets.SocketException">
/// A socket error occurred trying to connect to the remote host.
/// </exception>
/// <exception cref="SslHandshakeException">
/// An error occurred during the SSL/TLS negotiations.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// An IMAP command failed.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public override Task ConnectAsync (string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken))
{
return ConnectAsync (host, port, options, true, cancellationToken);
}
/// <summary>
/// Asynchronously establish a connection to the specified IMAP or IMAP/S server using the provided socket.
/// </summary>
/// <remarks>
/// <para>Establishes a connection to the specified IMAP or IMAP/S server using
/// the provided socket.</para>
/// <para>If the <paramref name="options"/> has a value of
/// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used
/// to determine the default security options. If the <paramref name="port"/> has a value
/// of <c>993</c>, then the default options used will be
/// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use
/// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para>
/// <para>Once a connection is established, properties such as
/// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be
/// populated.</para>
/// <note type="info">With the exception of using the <paramref name="port"/> to determine the
/// default <see cref="SecureSocketOptions"/> to use when the <paramref name="options"/> value
/// is <see cref="SecureSocketOptions.Auto"/>, the <paramref name="host"/> and
/// <paramref name="port"/> parameters are only used for logging purposes.</note>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="socket">The socket to use for the connection.</param>
/// <param name="host">The host name to connect to.</param>
/// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param>
/// <param name="options">The secure socket options to when connecting.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="socket"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="host"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para><paramref name="socket"/> is not connected.</para>
/// <para>-or-</para>
/// The <paramref name="host"/> is a zero-length string.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="ImapClient"/> has been disposed.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// The <see cref="ImapClient"/> is already connected.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <paramref name="options"/> was set to
/// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/>
/// and the IMAP server does not support the STARTTLS extension.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="SslHandshakeException">
/// An error occurred during the SSL/TLS negotiations.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// An IMAP command failed.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public override Task ConnectAsync (Socket socket, string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken))
{
return ConnectAsync (socket, host, port, options, true, cancellationToken);
}
/// <summary>
/// Asynchronously establish a connection to the specified IMAP or IMAP/S server using the provided stream.
/// </summary>
/// <remarks>
/// <para>Establishes a connection to the specified IMAP or IMAP/S server using
/// the provided stream.</para>
/// <para>If the <paramref name="options"/> has a value of
/// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used
/// to determine the default security options. If the <paramref name="port"/> has a value
/// of <c>993</c>, then the default options used will be
/// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use
/// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para>
/// <para>Once a connection is established, properties such as
/// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be
/// populated.</para>
/// <note type="info">With the exception of using the <paramref name="port"/> to determine the
/// default <see cref="SecureSocketOptions"/> to use when the <paramref name="options"/> value
/// is <see cref="SecureSocketOptions.Auto"/>, the <paramref name="host"/> and
/// <paramref name="port"/> parameters are only used for logging purposes.</note>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="stream">The stream to use for the connection.</param>
/// <param name="host">The host name to connect to.</param>
/// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param>
/// <param name="options">The secure socket options to when connecting.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="stream"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="host"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// The <paramref name="host"/> is a zero-length string.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="ImapClient"/> has been disposed.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// The <see cref="ImapClient"/> is already connected.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <paramref name="options"/> was set to
/// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/>
/// and the IMAP server does not support the STARTTLS extension.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="SslHandshakeException">
/// An error occurred during the SSL/TLS negotiations.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// An IMAP command failed.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public override Task ConnectAsync (Stream stream, string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken))
{
return ConnectAsync (stream, host, port, options, true, cancellationToken);
}
/// <summary>
/// Asynchronously disconnect the service.
/// </summary>
/// <remarks>
/// If <paramref name="quit"/> is <c>true</c>, a <c>LOGOUT</c> command will be issued in order to disconnect cleanly.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadMessages"/>
/// </example>
/// <returns>An asynchronous task context.</returns>
/// <param name="quit">If set to <c>true</c>, a <c>LOGOUT</c> command will be issued in order to disconnect cleanly.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="ImapClient"/> has been disposed.
/// </exception>
public override Task DisconnectAsync (bool quit, CancellationToken cancellationToken = default (CancellationToken))
{
return DisconnectAsync (quit, true, cancellationToken);
}
/// <summary>
/// Asynchronously ping the IMAP server to keep the connection alive.
/// </summary>
/// <remarks>
/// <para>The <c>NOOP</c> command is typically used to keep the connection with the IMAP server
/// alive. When a client goes too long (typically 30 minutes) without sending any commands to the
/// IMAP server, the IMAP server will close the connection with the client, forcing the client to
/// reconnect before it can send any more commands.</para>
/// <para>The <c>NOOP</c> command also provides a great way for a client to check for new
/// messages.</para>
/// <para>When the IMAP server receives a <c>NOOP</c> command, it will reply to the client with a
/// list of pending updates such as <c>EXISTS</c> and <c>RECENT</c> counts on the currently
/// selected folder. To receive these notifications, subscribe to the
/// <see cref="MailFolder.CountChanged"/> and <see cref="MailFolder.RecentChanged"/> events,
/// respectively.</para>
/// <para>For more information about the <c>NOOP</c> command, see
/// <a href="https://tools.ietf.org/html/rfc3501#section-6.1.2">rfc3501</a>.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapIdleExample.cs"/>
/// </example>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// The server replied to the NOOP command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
public override Task NoOpAsync (CancellationToken cancellationToken = default (CancellationToken))
{
return NoOpAsync (true, cancellationToken);
}
/// <summary>
/// Asynchronously toggle the <see cref="ImapClient"/> into the IDLE state.
/// </summary>
/// <remarks>
/// <para>When a client enters the IDLE state, the IMAP server will send
/// events to the client as they occur on the selected folder. These events
/// may include notifications of new messages arriving, expunge notifications,
/// flag changes, etc.</para>
/// <para>Due to the nature of the IDLE command, a folder must be selected
/// before a client can enter into the IDLE state. This can be done by
/// opening a folder using
/// <see cref="MailKit.MailFolder.Open(FolderAccess,System.Threading.CancellationToken)"/>
/// or any of the other variants.</para>
/// <para>While the IDLE command is running, no other commands may be issued until the
/// <paramref name="doneToken"/> is cancelled.</para>
/// <note type="note">It is especially important to cancel the <paramref name="doneToken"/>
/// before cancelling the <paramref name="cancellationToken"/> when using SSL or TLS due to
/// the fact that <see cref="System.Net.Security.SslStream"/> cannot be polled.</note>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="doneToken">The cancellation token used to return to the non-idle state.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentException">
/// <paramref name="doneToken"/> must be cancellable (i.e. <see cref="System.Threading.CancellationToken.None"/> cannot be used).
/// </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="System.InvalidOperationException">
/// A <see cref="ImapFolder"/> has not been opened.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the IDLE extension.
/// </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="ImapCommandException">
/// The server replied to the IDLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
public Task IdleAsync (CancellationToken doneToken, CancellationToken cancellationToken = default (CancellationToken))
{
return IdleAsync (doneToken, true, cancellationToken);
}
/// <summary>
/// Asynchronously request the specified notification events from the IMAP server.
/// </summary>
/// <remarks>
/// <para>The <a href="https://tools.ietf.org/html/rfc5465">NOTIFY</a> command is used to expand
/// which notifications the client wishes to be notified about, including status notifications
/// about folders other than the currently selected folder. It can also be used to automatically
/// FETCH information about new messages that have arrived in the currently selected folder.</para>
/// <para>This, combined with <see cref="IdleAsync(CancellationToken, CancellationToken)"/>,
/// can be used to get instant notifications for changes to any of the specified folders.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="status"><c>true</c> if the server should immediately notify the client of the
/// selected folder's status; otherwise, <c>false</c>.</param>
/// <param name="eventGroups">The specific event groups that the client would like to receive notifications for.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="eventGroups"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="eventGroups"/> is empty.
/// </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="System.InvalidOperationException">
/// One or more <see cref="ImapEventGroup"/> is invalid.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the NOTIFY extension.
/// </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="ImapCommandException">
/// The server replied to the NOTIFY command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
public Task NotifyAsync (bool status, IList<ImapEventGroup> eventGroups, CancellationToken cancellationToken = default (CancellationToken))
{
return NotifyAsync (status, eventGroups, true, cancellationToken);
}
/// <summary>
/// Asynchronously disable any previously requested notification events from the IMAP server.
/// </summary>
/// <remarks>
/// Disables any notification events requested in a prior call to
/// <see cref="NotifyAsync(bool, IList{ImapEventGroup}, CancellationToken)"/>.
/// request.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the NOTIFY extension.
/// </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="ImapCommandException">
/// The server replied to the NOTIFY command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
public Task DisableNotifyAsync (CancellationToken cancellationToken = default (CancellationToken))
{
return DisableNotifyAsync (true, cancellationToken);
}
/// <summary>
/// Asynchronously get all of the folders within the specified namespace.
/// </summary>
/// <remarks>
/// Gets all of the folders within the specified namespace.
/// </remarks>
/// <returns>The folders.</returns>
/// <param name="namespace">The namespace.</param>
/// <param name="items">The status items to pre-populate.</param>
/// <param name="subscribedOnly">If set to <c>true</c>, only subscribed folders will be listed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="namespace"/> 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="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The namespace folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// The server replied to the LIST or LSUB command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
public override Task<IList<IMailFolder>> GetFoldersAsync (FolderNamespace @namespace, StatusItems items = StatusItems.None, bool subscribedOnly = false, CancellationToken cancellationToken = default (CancellationToken))
{
return GetFoldersAsync (@namespace, items, subscribedOnly, true, cancellationToken);
}
/// <summary>
/// Asynchronously get the folder for the specified path.
/// </summary>
/// <remarks>
/// Gets the folder for the specified path.
/// </remarks>
/// <returns>The folder.</returns>
/// <param name="path">The folder path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="path"/> 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="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="FolderNotFoundException">
/// The folder could not be found.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapCommandException">
/// The server replied to the IDLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
public override async Task<IMailFolder> GetFolderAsync (string path, CancellationToken cancellationToken = default (CancellationToken))
{
if (path == null)
throw new ArgumentNullException (nameof (path));
CheckDisposed ();
CheckConnected ();
CheckAuthenticated ();
return await engine.GetFolderAsync (path, true, cancellationToken).ConfigureAwait (false);
}
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata value.</returns>
/// <param name="tag">The metadata tag.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the METADATA or METADATA-SERVER extension.
/// </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<string> GetMetadataAsync (MetadataTag tag, CancellationToken cancellationToken = default (CancellationToken))
{
return GetMetadataAsync (tag, true, cancellationToken);
}
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Gets the specified metadata.
/// </remarks>
/// <returns>The requested metadata.</returns>
/// <param name="options">The metadata options.</param>
/// <param name="tags">The metadata tags.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="tags"/> is <c>null</c>.</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="System.NotSupportedException">
/// The IMAP server does not support the METADATA or METADATA-SERVER extension.
/// </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<MetadataCollection> GetMetadataAsync (MetadataOptions options, IEnumerable<MetadataTag> tags, CancellationToken cancellationToken = default (CancellationToken))
{
return GetMetadataAsync (options, tags, true, cancellationToken);
}
/// <summary>
/// Asynchronously gets the specified metadata.
/// </summary>
/// <remarks>
/// Sets the specified metadata.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="metadata">The metadata.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="metadata"/> 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="System.NotSupportedException">
/// The IMAP server does not support the METADATA or METADATA-SERVER extension.
/// </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 SetMetadataAsync (MetadataCollection metadata, CancellationToken cancellationToken = default (CancellationToken))
{
return SetMetadataAsync (metadata, true, cancellationToken);
}
}
}

View File

@ -0,0 +1,628 @@
//
// IImapClient.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace MailKit.Net.Imap {
/// <summary>
/// An interface for an IMAP client.
/// </summary>
/// <remarks>
/// Implemented by <see cref="MailKit.Net.Imap.ImapClient"/>.
/// </remarks>
public interface IImapClient : IMailStore
{
/// <summary>
/// Get the capabilities supported by the IMAP server.
/// </summary>
/// <remarks>
/// The capabilities will not be known until a successful connection has been made via one of
/// the <a href="Overload_MailKit_Net_Imap_ImapClient_Connect.htm">Connect</a> methods and may
/// change as a side-effect of calling one of the
/// <a href="Overload_MailKit_Net_Imap_ImapClient_Authenticate.htm">Authenticate</a>
/// methods.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The capabilities.</value>
/// <exception cref="System.ArgumentException">
/// Capabilities cannot be enabled, they may only be disabled.
/// </exception>
ImapCapabilities Capabilities { get; set; }
/// <summary>
/// Gets the maximum size of a message that can be appended to a folder.
/// </summary>
/// <remarks>
/// <para>Gets the maximum size of a message, in bytes, that can be appended to a folder.</para>
/// <note type="note">If the value is not set, then the limit is unspecified.</note>
/// </remarks>
/// <value>The append limit.</value>
uint? AppendLimit { get; }
/// <summary>
/// Gets the internationalization level supported by the IMAP server.
/// </summary>
/// <remarks>
/// <para>Gets the internationalization level supported by the IMAP server.</para>
/// <para>For more information, see
/// <a href="https://tools.ietf.org/html/rfc5255#section-4">section 4 of rfc5255</a>.</para>
/// </remarks>
/// <value>The internationalization level.</value>
int InternationalizationLevel { get; }
/// <summary>
/// Get the access rights supported by the IMAP server.
/// </summary>
/// <remarks>
/// These rights are additional rights supported by the IMAP server beyond the standard rights
/// defined in <a href="https://tools.ietf.org/html/rfc4314#section-2.1">section 2.1 of rfc4314</a>
/// and will not be populated until the client is successfully connected.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The rights.</value>
AccessRights Rights { get; }
/// <summary>
/// Get whether or not the client is currently in the IDLE state.
/// </summary>
/// <remarks>
/// Gets whether or not the client is currently in the IDLE state.
/// </remarks>
/// <value><c>true</c> if an IDLE command is active; otherwise, <c>false</c>.</value>
bool IsIdle { get; }
/// <summary>
/// Enable compression over the IMAP connection.
/// </summary>
/// <remarks>
/// <para>Enables compression over the IMAP connection.</para>
/// <para>If the IMAP server supports the <see cref="ImapCapabilities.Compress"/> extension,
/// it is possible at any point after connecting to enable compression to reduce network
/// bandwidth usage. Ideally, this method should be called before authenticating.</para>
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// Compression must be enabled before a folder has been selected.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the <see cref="ImapCapabilities.Compress"/> extension.
/// </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="ImapCommandException">
/// The server replied to the COMPRESS command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
void Compress (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously enable compression over the IMAP connection.
/// </summary>
/// <remarks>
/// <para>Asynchronously enables compression over the IMAP connection.</para>
/// <para>If the IMAP server supports the <see cref="ImapCapabilities.Compress"/> extension,
/// it is possible at any point after connecting to enable compression to reduce network
/// bandwidth usage. Ideally, this method should be called before authenticating.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// Compression must be enabled before a folder has been selected.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the COMPRESS extension.
/// </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="ImapCommandException">
/// The server replied to the COMPRESS command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
Task CompressAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Enable the UTF8=ACCEPT extension.
/// </summary>
/// <remarks>
/// Enables the <a href="https://tools.ietf.org/html/rfc6855">UTF8=ACCEPT</a> extension.
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// UTF8=ACCEPT needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the UTF8=ACCEPT extension.
/// </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="ImapCommandException">
/// The server replied to the ENABLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
void EnableUTF8 (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously enable the UTF8=ACCEPT extension.
/// </summary>
/// <remarks>
/// Enables the <a href="https://tools.ietf.org/html/rfc6855">UTF8=ACCEPT</a> extension.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.InvalidOperationException">
/// UTF8=ACCEPT needs to be enabled before selecting a folder.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the UTF8=ACCEPT extension.
/// </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="ImapCommandException">
/// The server replied to the ENABLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
Task EnableUTF8Async (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Identify the client implementation to the server and obtain the server implementation details.
/// </summary>
/// <remarks>
/// <para>Passes along the client implementation details to the server while also obtaining implementation
/// details from the server.</para>
/// <para>If the <paramref name="clientImplementation"/> is <c>null</c> or no properties have been set, no
/// identifying information will be sent to the server.</para>
/// <note type="security">
/// <para>Security Implications</para>
/// <para>This command has the danger of violating the privacy of users if misused. Clients should
/// notify users that they send the ID command.</para>
/// <para>It is highly desirable that implementations provide a method of disabling ID support, perhaps by
/// not calling this method at all, or by passing <c>null</c> as the <paramref name="clientImplementation"/>
/// argument.</para>
/// <para>Implementors must exercise extreme care in adding properties to the <paramref name="clientImplementation"/>.
/// Some properties, such as a processor ID number, Ethernet address, or other unique (or mostly unique) identifier
/// would allow tracking of users in ways that violate user privacy expectations and may also make it easier for
/// attackers to exploit security holes in the client.</para>
/// </note>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <returns>The implementation details of the server if available; otherwise, <c>null</c>.</returns>
/// <param name="clientImplementation">The client implementation.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the ID extension.
/// </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="ImapCommandException">
/// The server replied to the ID command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
ImapImplementation Identify (ImapImplementation clientImplementation, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously identify the client implementation to the server and obtain the server implementation details.
/// </summary>
/// <remarks>
/// <para>Passes along the client implementation details to the server while also obtaining implementation
/// details from the server.</para>
/// <para>If the <paramref name="clientImplementation"/> is <c>null</c> or no properties have been set, no
/// identifying information will be sent to the server.</para>
/// <note type="security">
/// <para>Security Implications</para>
/// <para>This command has the danger of violating the privacy of users if misused. Clients should
/// notify users that they send the ID command.</para>
/// <para>It is highly desirable that implementations provide a method of disabling ID support, perhaps by
/// not calling this method at all, or by passing <c>null</c> as the <paramref name="clientImplementation"/>
/// argument.</para>
/// <para>Implementors must exercise extreme care in adding properties to the <paramref name="clientImplementation"/>.
/// Some properties, such as a processor ID number, Ethernet address, or other unique (or mostly unique) identifier
/// would allow tracking of users in ways that violate user privacy expectations and may also make it easier for
/// attackers to exploit security holes in the client.</para>
/// </note>
/// </remarks>
/// <returns>The implementation details of the server if available; otherwise, <c>null</c>.</returns>
/// <param name="clientImplementation">The client implementation.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the ID extension.
/// </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="ImapCommandException">
/// The server replied to the ID command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
Task<ImapImplementation> IdentifyAsync (ImapImplementation clientImplementation, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Toggle the <see cref="ImapClient"/> into the IDLE state.
/// </summary>
/// <remarks>
/// <para>When a client enters the IDLE state, the IMAP server will send
/// events to the client as they occur on the selected folder. These events
/// may include notifications of new messages arriving, expunge notifications,
/// flag changes, etc.</para>
/// <para>Due to the nature of the IDLE command, a folder must be selected
/// before a client can enter into the IDLE state. This can be done by
/// opening a folder using
/// <see cref="MailKit.MailFolder.Open(FolderAccess,System.Threading.CancellationToken)"/>
/// or any of the other variants.</para>
/// <para>While the IDLE command is running, no other commands may be issued until the
/// <paramref name="doneToken"/> is cancelled.</para>
/// <note type="note">It is especially important to cancel the <paramref name="doneToken"/>
/// before cancelling the <paramref name="cancellationToken"/> when using SSL or TLS due to
/// the fact that <see cref="System.Net.Security.SslStream"/> cannot be polled.</note>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapIdleExample.cs"/>
/// </example>
/// <param name="doneToken">The cancellation token used to return to the non-idle state.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentException">
/// <paramref name="doneToken"/> must be cancellable (i.e. <see cref="System.Threading.CancellationToken.None"/> cannot be used).
/// </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="System.InvalidOperationException">
/// A <see cref="ImapFolder"/> has not been opened.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the IDLE extension.
/// </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="ImapCommandException">
/// The server replied to the IDLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
void Idle (CancellationToken doneToken, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously toggle the <see cref="ImapClient"/> into the IDLE state.
/// </summary>
/// <remarks>
/// <para>When a client enters the IDLE state, the IMAP server will send
/// events to the client as they occur on the selected folder. These events
/// may include notifications of new messages arriving, expunge notifications,
/// flag changes, etc.</para>
/// <para>Due to the nature of the IDLE command, a folder must be selected
/// before a client can enter into the IDLE state. This can be done by
/// opening a folder using
/// <see cref="MailKit.MailFolder.Open(FolderAccess,System.Threading.CancellationToken)"/>
/// or any of the other variants.</para>
/// <para>While the IDLE command is running, no other commands may be issued until the
/// <paramref name="doneToken"/> is cancelled.</para>
/// <note type="note">It is especially important to cancel the <paramref name="doneToken"/>
/// before cancelling the <paramref name="cancellationToken"/> when using SSL or TLS due to
/// the fact that <see cref="System.Net.Security.SslStream"/> cannot be polled.</note>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="doneToken">The cancellation token used to return to the non-idle state.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentException">
/// <paramref name="doneToken"/> must be cancellable (i.e. <see cref="System.Threading.CancellationToken.None"/> cannot be used).
/// </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="System.InvalidOperationException">
/// A <see cref="ImapFolder"/> has not been opened.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the IDLE extension.
/// </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="ImapCommandException">
/// The server replied to the IDLE command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
Task IdleAsync (CancellationToken doneToken, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Request the specified notification events from the IMAP server.
/// </summary>
/// <remarks>
/// <para>The <a href="https://tools.ietf.org/html/rfc5465">NOTIFY</a> command is used to expand
/// which notifications the client wishes to be notified about, including status notifications
/// about folders other than the currently selected folder. It can also be used to automatically
/// FETCH information about new messages that have arrived in the currently selected folder.</para>
/// <para>This, combined with <see cref="Idle(CancellationToken, CancellationToken)"/>,
/// can be used to get instant notifications for changes to any of the specified folders.</para>
/// </remarks>
/// <param name="status"><c>true</c> if the server should immediately notify the client of the
/// selected folder's status; otherwise, <c>false</c>.</param>
/// <param name="eventGroups">The specific event groups that the client would like to receive notifications for.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="eventGroups"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="eventGroups"/> is empty.
/// </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="System.InvalidOperationException">
/// One or more <see cref="ImapEventGroup"/> is invalid.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the NOTIFY extension.
/// </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="ImapCommandException">
/// The server replied to the NOTIFY command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
void Notify (bool status, IList<ImapEventGroup> eventGroups, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously request the specified notification events from the IMAP server.
/// </summary>
/// <remarks>
/// <para>The <a href="https://tools.ietf.org/html/rfc5465">NOTIFY</a> command is used to expand
/// which notifications the client wishes to be notified about, including status notifications
/// about folders other than the currently selected folder. It can also be used to automatically
/// FETCH information about new messages that have arrived in the currently selected folder.</para>
/// <para>This, combined with <see cref="IdleAsync(CancellationToken, CancellationToken)"/>,
/// can be used to get instant notifications for changes to any of the specified folders.</para>
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="status"><c>true</c> if the server should immediately notify the client of the
/// selected folder's status; otherwise, <c>false</c>.</param>
/// <param name="eventGroups">The specific event groups that the client would like to receive notifications for.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="eventGroups"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="eventGroups"/> is empty.
/// </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="System.InvalidOperationException">
/// One or more <see cref="ImapEventGroup"/> is invalid.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the NOTIFY extension.
/// </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="ImapCommandException">
/// The server replied to the NOTIFY command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
Task NotifyAsync (bool status, IList<ImapEventGroup> eventGroups, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Disable any previously requested notification events from the IMAP server.
/// </summary>
/// <remarks>
/// Disables any notification events requested in a prior call to
/// <see cref="Notify(bool, IList{ImapEventGroup}, CancellationToken)"/>.
/// request.
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the NOTIFY extension.
/// </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="ImapCommandException">
/// The server replied to the NOTIFY command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
void DisableNotify (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously disable any previously requested notification events from the IMAP server.
/// </summary>
/// <remarks>
/// Disables any notification events requested in a prior call to
/// <see cref="NotifyAsync(bool, IList{ImapEventGroup}, CancellationToken)"/>.
/// request.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <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="System.NotSupportedException">
/// The IMAP server does not support the NOTIFY extension.
/// </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="ImapCommandException">
/// The server replied to the NOTIFY command with a NO or BAD response.
/// </exception>
/// <exception cref="ImapProtocolException">
/// The server responded with an unexpected token.
/// </exception>
Task DisableNotifyAsync (CancellationToken cancellationToken = default (CancellationToken));
}
}

View File

@ -0,0 +1,869 @@
//
// IImapFolder.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using MimeKit;
using MailKit.Search;
namespace MailKit.Net.Imap {
/// <summary>
/// An interface for an IMAP folder.
/// </summary>
/// <remarks>
/// Implemented by <see cref="MailKit.Net.Imap.ImapFolder"/>.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadMessages"/>
/// </example>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadBodyParts"/>
/// </example>
public interface IImapFolder : IMailFolder
{
/// <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>
HeaderList GetHeaders (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task<HeaderList> GetHeadersAsync (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
HeaderList GetHeaders (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task<HeaderList> GetHeadersAsync (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
MimeEntity GetBodyPart (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task<MimeEntity> GetBodyPartAsync (UniqueId uid, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
MimeEntity GetBodyPart (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task<MimeEntity> GetBodyPartAsync (int index, string partSpecifier, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
void GetStreams (IList<UniqueId> uids, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task GetStreamsAsync (IList<UniqueId> uids, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
void GetStreams (IList<int> indexes, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task GetStreamsAsync (IList<int> indexes, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
void GetStreams (int min, int max, ImapFetchStreamCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <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>
Task GetStreamsAsync (int min, int max, ImapFetchStreamAsyncCallback callback, CancellationToken cancellationToken = default (CancellationToken), ITransferProgress progress = null);
/// <summary>
/// Search the folder for messages matching the specified query.
/// </summary>
/// <remarks>
/// Sends a <c>UID SEARCH</c> command with the specified query passed directly to the IMAP server
/// with no interpretation by MailKit. This means that the query may contain any arguments that a
/// <c>UID SEARCH</c> command is allowed to have according to the IMAP specifications and any
/// extensions that are supported, including <c>RETURN</c> parameters.
/// </remarks>
/// <returns>An array of matching UIDs.</returns>
/// <param name="query">The search query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="query"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="query"/> is an empty string.
/// </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>
SearchResults Search (string query, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously search the folder for messages matching the specified query.
/// </summary>
/// <remarks>
/// Sends a <c>UID SEARCH</c> command with the specified query passed directly to the IMAP server
/// with no interpretation by MailKit. This means that the query may contain any arguments that a
/// <c>UID SEARCH</c> command is allowed to have according to the IMAP specifications and any
/// extensions that are supported, including <c>RETURN</c> parameters.
/// </remarks>
/// <returns>An array of matching UIDs.</returns>
/// <param name="query">The search query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="query"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="query"/> is an empty string.
/// </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>
Task<SearchResults> SearchAsync (string query, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Sort messages matching the specified query.
/// </summary>
/// <remarks>
/// Sends a <c>UID SORT</c> command with the specified query passed directly to the IMAP server
/// with no interpretation by MailKit. This means that the query may contain any arguments that a
/// <c>UID SORT</c> command is allowed to have according to the IMAP specifications and any
/// extensions that are supported, including <c>RETURN</c> parameters.
/// </remarks>
/// <returns>An array of matching UIDs.</returns>
/// <param name="query">The search query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="query"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="query"/> is an empty string.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the SORT extension.
/// </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>
SearchResults Sort (string query, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously sort messages matching the specified query.
/// </summary>
/// <remarks>
/// Sends a <c>UID SORT</c> command with the specified query passed directly to the IMAP server
/// with no interpretation by MailKit. This means that the query may contain any arguments that a
/// <c>UID SORT</c> command is allowed to have according to the IMAP specifications and any
/// extensions that are supported, including <c>RETURN</c> parameters.
/// </remarks>
/// <returns>An array of matching UIDs.</returns>
/// <param name="query">The search query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="query"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="query"/> is an empty string.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The IMAP server does not support the SORT extension.
/// </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>
Task<SearchResults> SortAsync (string query, CancellationToken cancellationToken = default (CancellationToken));
}
}

View File

@ -0,0 +1,68 @@
//
// ImapCallbacks.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.IO;
using System.Threading;
using System.Threading.Tasks;
namespace MailKit.Net.Imap
{
/// <summary>
/// A callback used when fetching message streams.
/// </summary>
/// <remarks>
/// <para>This callback is meant to be used with the various
/// <a href="Overload_MailKit_Net_Imap_ImapFolder_GetStreams.htm">GetStreams</a>
/// methods.</para>
/// <para>Once this callback returns, the stream argument will be disposed, so
/// it is important to consume the stream right away and not add it to a queue
/// for later processing.</para>
/// </remarks>
/// <param name="folder">The IMAP folder that the message belongs to.</param>
/// <param name="index">The index of the message in the folder.</param>
/// <param name="uid">The UID of the message in the folder.</param>
/// <param name="stream">The raw message (or part) stream.</param>
public delegate void ImapFetchStreamCallback (ImapFolder folder, int index, UniqueId uid, Stream stream);
/// <summary>
/// An asynchronous callback used when fetching message streams.
/// </summary>
/// <remarks>
/// <para>This callback is meant to be used with the various
/// <a href="Overload_MailKit_Net_Imap_ImapFolder_GetStreamsAsync.htm">GetStreamsAsync</a>
/// methods.</para>
/// <para>Once this callback returns, the stream argument will be disposed, so
/// it is important to consume the stream right away and not add it to a queue
/// for later processing.</para>
/// </remarks>
/// <returns>An awaitable task context.</returns>
/// <param name="folder">The IMAP folder that the message belongs to.</param>
/// <param name="index">The index of the message in the folder.</param>
/// <param name="uid">The UID of the message in the folder.</param>
/// <param name="stream">The raw message (or part) stream.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public delegate Task ImapFetchStreamAsyncCallback (ImapFolder folder, int index, UniqueId uid, Stream stream, CancellationToken cancellationToken);
}

View File

@ -0,0 +1,348 @@
//
// ImapCapabilities.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;
namespace MailKit.Net.Imap {
/// <summary>
/// Capabilities supported by an IMAP server.
/// </summary>
/// <remarks>
/// Capabilities are read as part of the response to the <c>CAPABILITY</c> command that
/// is issued during the connection and authentication phases of the
/// <see cref="ImapClient"/>.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
[Flags]
public enum ImapCapabilities : ulong {
/// <summary>
/// The server does not support any additional extensions.
/// </summary>
None = 0,
/// <summary>
/// The server implements the core IMAP4 commands.
/// </summary>
IMAP4 = 1L << 0,
/// <summary>
/// The server implements the core IMAP4rev1 commands.
/// </summary>
IMAP4rev1 = 1L << 1,
/// <summary>
/// The server implements the core IMAP4rev2 commands.
/// </summary>
IMAP4rev2 = 1L << 2,
/// <summary>
/// The server supports the <c>STATUS</c> command.
/// </summary>
Status = 1L << 3,
/// <summary>
/// The server supports the ACL extension defined in <a href="https://tools.ietf.org/html/rfc2086">rfc2086</a>
/// and <a href="https://tools.ietf.org/html/rfc4314">rfc4314</a>.
/// </summary>
Acl = 1L << 4,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2087">QUOTA</a> extension.
/// </summary>
Quota = 1L << 5,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2088">LITERAL+</a> extension.
/// </summary>
LiteralPlus = 1L << 6,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2177">IDLE</a> extension.
/// </summary>
Idle = 1L << 7,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2193">MAILBOX-REFERRALS</a> extension.
/// </summary>
MailboxReferrals = 1L << 8,
/// <summary>
/// the server supports the <a href="https://tools.ietf.org/html/rfc2221">LOGIN-REFERRALS</a> extension.
/// </summary>
LoginReferrals = 1L << 9,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2342">NAMESPACE</a> extension.
/// </summary>
Namespace = 1L << 10,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2971">ID</a> extension.
/// </summary>
Id = 1L << 11,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc3348">CHILDREN</a> extension.
/// </summary>
Children = 1L << 12,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc3501">LOGINDISABLED</a> extension.
/// </summary>
LoginDisabled = 1L << 13,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc3501">STARTTLS</a> extension.
/// </summary>
StartTLS = 1L << 14,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc3502">MULTIAPPEND</a> extension.
/// </summary>
MultiAppend = 1L << 15,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc3516">BINARY</a> content extension.
/// </summary>
Binary = 1L << 16,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc3691">UNSELECT</a> extension.
/// </summary>
Unselect = 1L << 17,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc4315">UIDPLUS</a> extension.
/// </summary>
UidPlus = 1L << 18,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc4469">CATENATE</a> extension.
/// </summary>
Catenate = 1L << 19,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc4551">CONDSTORE</a> extension.
/// </summary>
CondStore = 1L << 20,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc4731">ESEARCH</a> extension.
/// </summary>
ESearch = 1L << 21,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc4959">SASL-IR</a> extension.
/// </summary>
SaslIR = 1L << 22,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc4978">COMPRESS</a> extension.
/// </summary>
Compress = 1L << 23,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5032">WITHIN</a> extension.
/// </summary>
Within = 1L << 24,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5161">ENABLE</a> extension.
/// </summary>
Enable = 1L << 25,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5162">QRESYNC</a> extension.
/// </summary>
QuickResync = 1L << 26,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5182">SEARCHRES</a> extension.
/// </summary>
SearchResults = 1L << 27,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5256">SORT</a> extension.
/// </summary>
Sort = 1L << 28,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5256">THREAD</a> extension.
/// </summary>
Thread = 1L << 29,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5257">ANNOTATE</a> extension.
/// </summary>
Annotate = 1L << 30,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5258">LIST-EXTENDED</a> extension.
/// </summary>
ListExtended = 1L << 31,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5259">CONVERT</a> extension.
/// </summary>
Convert = 1L << 32,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5255">LANGUAGE</a> extension.
/// </summary>
Language = 1L << 33,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5255">I18NLEVEL</a> extension.
/// </summary>
I18NLevel = 1L << 34,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5267">ESORT</a> extension.
/// </summary>
ESort = 1L << 35,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5267">CONTEXT</a> extension.
/// </summary>
Context = 1L << 36,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5464">METADATA</a> extension.
/// </summary>
Metadata = 1L << 37,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5464">METADATA-SERVER</a> extension.
/// </summary>
MetadataServer = 1L << 38,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5465">NOTIFY</a> extension.
/// </summary>
Notify = 1L << 39,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5466">FILTERS</a> extension.
/// </summary>
Filters = 1L << 40,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5819">LIST-STATUS</a> extension.
/// </summary>
ListStatus = 1L << 41,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc5957">SORT=DISPLAY</a> extension.
/// </summary>
SortDisplay = 1L << 42,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6154">CREATE-SPECIAL-USE</a> extension.
/// </summary>
CreateSpecialUse = 1L << 43,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6154">SPECIAL-USE</a> extension.
/// </summary>
SpecialUse = 1L << 44,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6203">SEARCH=FUZZY</a> extension.
/// </summary>
FuzzySearch = 1L << 45,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6237">MULTISEARCH</a> extension.
/// </summary>
MultiSearch = 1L << 46,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6851">MOVE</a> extension.
/// </summary>
Move = 1L << 47,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6855">UTF8=ACCEPT</a> extension.
/// </summary>
UTF8Accept = 1L << 48,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6855">UTF8=ONLY</a> extension.
/// </summary>
UTF8Only = 1L << 49,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc7888">LITERAL-</a> extension.
/// </summary>
LiteralMinus = 1L << 50,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc7889">APPENDLIMIT</a> extension.
/// </summary>
AppendLimit = 1L << 51,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc8437">UNAUTHENTICATE</a> extension.
/// </summary>
Unauthenticate = 1L << 52,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc8438">STATUS=SIZE</a> extension.
/// </summary>
StatusSize = 1L << 53,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc8440">LIST-MYRIGHTS</a> extension.
/// </summary>
ListMyRights = 1L << 54,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc8474">OBJECTID</a> extension.
/// </summary>
ObjectID = 1L << 55,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc8508">REPLACE</a> extension.
/// </summary>
Replace = 1L << 56,
#region GMail Extensions
/// <summary>
/// The server supports the <a href="https://developers.google.com/gmail/imap_extensions">XLIST</a> extension (GMail).
/// </summary>
XList = 1L << 60,
/// <summary>
/// The server supports the <a href="https://developers.google.com/gmail/imap_extensions">X-GM-EXT1</a> extension (GMail).
/// </summary>
GMailExt1 = 1L << 61
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,918 @@
//
// ImapCommand.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.Text;
using System.Threading;
using System.Globalization;
using System.Threading.Tasks;
using System.Collections.Generic;
using MimeKit;
using MimeKit.IO;
using MimeKit.Utils;
using SslStream = MailKit.Net.SslStream;
using NetworkStream = MailKit.Net.NetworkStream;
namespace MailKit.Net.Imap {
/// <summary>
/// An IMAP continuation handler.
/// </summary>
/// <remarks>
/// All exceptions thrown by the handler are considered fatal and will
/// force-disconnect the connection. If a non-fatal error occurs, set
/// it on the <see cref="ImapCommand.Exception"/> property.
/// </remarks>
delegate Task ImapContinuationHandler (ImapEngine engine, ImapCommand ic, string text, bool doAsync);
/// <summary>
/// An IMAP untagged response handler.
/// </summary>
/// <remarks>
/// <para>Most IMAP commands return their results in untagged responses.</para>
/// </remarks>
delegate Task ImapUntaggedHandler (ImapEngine engine, ImapCommand ic, int index, bool doAsync);
delegate void ImapCommandResetHandler (ImapCommand ic);
/// <summary>
/// IMAP command status.
/// </summary>
enum ImapCommandStatus {
Created,
Queued,
Active,
Complete,
Error
}
enum ImapLiteralType {
String,
//Stream,
MimeMessage
}
enum ImapStringType {
Atom,
QString,
Literal,
Nil
}
/// <summary>
/// An IMAP IDLE context.
/// </summary>
/// <remarks>
/// <para>An IMAP IDLE command does not work like normal commands. Unlike most commands,
/// the IDLE command does not end until the client sends a separate "DONE" command.</para>
/// <para>In order to facilitate this, the way this works is that the consumer of MailKit's
/// IMAP APIs provides a 'doneToken' which signals to the command-processing loop to
/// send the "DONE" command. Since, like every other IMAP command, it is also necessary to
/// provide a means of cancelling the IDLE command, it becomes necessary to link the
/// 'doneToken' and the 'cancellationToken' together.</para>
/// </remarks>
sealed class ImapIdleContext : IDisposable
{
static readonly byte[] DoneCommand = Encoding.ASCII.GetBytes ("DONE\r\n");
CancellationTokenRegistration registration;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapIdleContext"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapIdleContext"/>.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="doneToken">The done token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public ImapIdleContext (ImapEngine engine, CancellationToken doneToken, CancellationToken cancellationToken)
{
CancellationToken = cancellationToken;
DoneToken = doneToken;
Engine = engine;
}
/// <summary>
/// Get the engine.
/// </summary>
/// <remarks>
/// Gets the engine.
/// </remarks>
/// <value>The engine.</value>
public ImapEngine Engine {
get; private set;
}
/// <summary>
/// Get the cancellation token.
/// </summary>
/// <remarks>
/// Get the cancellation token.
/// </remarks>
/// <value>The cancellation token.</value>
public CancellationToken CancellationToken {
get; private set;
}
/// <summary>
/// Get the done token.
/// </summary>
/// <remarks>
/// Gets the done token.
/// </remarks>
/// <value>The done token.</value>
public CancellationToken DoneToken {
get; private set;
}
#if false
/// <summary>
/// Get whether or not cancellation has been requested.
/// </summary>
/// <remarks>
/// Gets whether or not cancellation has been requested.
/// </remarks>
/// <value><c>true</c> if cancellation has been requested; otherwise, <c>false</c>.</value>
public bool IsCancellationRequested {
get { return CancellationToken.IsCancellationRequested; }
}
/// <summary>
/// Get whether or not the IDLE command should be ended.
/// </summary>
/// <remarks>
/// Gets whether or not the IDLE command should be ended.
/// </remarks>
/// <value><c>true</c> if the IDLE command should end; otherwise, <c>false</c>.</value>
public bool IsDoneRequested {
get { return DoneToken.IsCancellationRequested; }
}
#endif
void IdleComplete ()
{
if (Engine.State == ImapEngineState.Idle) {
try {
Engine.Stream.Write (DoneCommand, 0, DoneCommand.Length, CancellationToken);
Engine.Stream.Flush (CancellationToken);
} catch {
return;
}
Engine.State = ImapEngineState.Selected;
}
}
/// <summary>
/// Callback method to be used as the ImapCommand's ContinuationHandler.
/// </summary>
/// <remarks>
/// Callback method to be used as the ImapCommand's ContinuationHandler.
/// </remarks>
/// <param name="engine">The ImapEngine.</param>
/// <param name="ic">The ImapCommand.</param>
/// <param name="text">The text.</param>
/// <param name="doAsync"><c>true</c> if the command is being run asynchronously; otherwise, <c>false</c>.</param>
/// <returns></returns>
public Task ContinuationHandler (ImapEngine engine, ImapCommand ic, string text, bool doAsync)
{
Engine.State = ImapEngineState.Idle;
registration = DoneToken.Register (IdleComplete);
return Task.FromResult (true);
}
/// <summary>
/// Releases all resource used by the <see cref="MailKit.Net.Imap.ImapIdleContext"/> object.
/// </summary>
/// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="MailKit.Net.Imap.ImapIdleContext"/>. The
/// <see cref="Dispose"/> method leaves the <see cref="MailKit.Net.Imap.ImapIdleContext"/> in an unusable state. After
/// calling <see cref="Dispose"/>, you must release all references to the
/// <see cref="MailKit.Net.Imap.ImapIdleContext"/> so the garbage collector can reclaim the memory that the
/// <see cref="MailKit.Net.Imap.ImapIdleContext"/> was occupying.</remarks>
public void Dispose ()
{
registration.Dispose ();
}
}
/// <summary>
/// An IMAP literal object.
/// </summary>
/// <remarks>
/// The literal can be a string, byte[], Stream, or a MimeMessage.
/// </remarks>
class ImapLiteral
{
public readonly ImapLiteralType Type;
public readonly object Literal;
readonly FormatOptions format;
readonly Action<int> update;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>.
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="message">The message.</param>
/// <param name="action">The progress update action.</param>
public ImapLiteral (FormatOptions options, MimeMessage message, Action<int> action = null)
{
format = options.Clone ();
format.NewLineFormat = NewLineFormat.Dos;
update = action;
Type = ImapLiteralType.MimeMessage;
Literal = message;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapLiteral"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapLiteral"/>.
/// </remarks>
/// <param name="options">The formatting options.</param>
/// <param name="literal">The literal.</param>
public ImapLiteral (FormatOptions options, byte[] literal)
{
format = options.Clone ();
format.NewLineFormat = NewLineFormat.Dos;
Type = ImapLiteralType.String;
Literal = literal;
}
/// <summary>
/// Get the length of the literal, in bytes.
/// </summary>
/// <remarks>
/// Gets the length of the literal, in bytes.
/// </remarks>
/// <value>The length.</value>
public long Length {
get {
if (Type == ImapLiteralType.String)
return ((byte[]) Literal).Length;
using (var measure = new MeasuringStream ()) {
//if (Type == ImapLiteralType.Stream) {
// var stream = (Stream) Literal;
// stream.CopyTo (measure, 4096);
// stream.Position = 0;
// return measure.Length;
//}
((MimeMessage) Literal).WriteTo (format, measure);
return measure.Length;
}
}
}
/// <summary>
/// Write the literal to the specified stream.
/// </summary>
/// <remarks>
/// Writes the literal to the specified stream.
/// </remarks>
/// <param name="stream">The stream.</param>
/// <param name="doAsync">Whether the literal should be written asynchronously or not.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public async Task WriteToAsync (ImapStream stream, bool doAsync, CancellationToken cancellationToken)
{
if (Type == ImapLiteralType.String) {
var bytes = (byte[]) Literal;
if (doAsync) {
await stream.WriteAsync (bytes, 0, bytes.Length, cancellationToken).ConfigureAwait (false);
await stream.FlushAsync (cancellationToken).ConfigureAwait (false);
} else {
stream.Write (bytes, 0, bytes.Length, cancellationToken);
stream.Flush (cancellationToken);
}
return;
}
//if (Type == ImapLiteralType.Stream) {
// var literal = (Stream) Literal;
// var buf = new byte[4096];
// int nread;
// if (doAsync) {
// while ((nread = await literal.ReadAsync (buf, 0, buf.Length, cancellationToken).ConfigureAwait (false)) > 0)
// await stream.WriteAsync (buf, 0, nread, cancellationToken).ConfigureAwait (false);
// await stream.FlushAsync (cancellationToken).ConfigureAwait (false);
// } else {
// while ((nread = literal.Read (buf, 0, buf.Length)) > 0)
// stream.Write (buf, 0, nread, cancellationToken);
// stream.Flush (cancellationToken);
// }
// return;
//}
var message = (MimeMessage) Literal;
using (var s = new ProgressStream (stream, update)) {
if (doAsync) {
await message.WriteToAsync (format, s, cancellationToken).ConfigureAwait (false);
await s.FlushAsync (cancellationToken).ConfigureAwait (false);
} else {
message.WriteTo (format, s, cancellationToken);
s.Flush (cancellationToken);
}
}
}
}
/// <summary>
/// A partial IMAP command.
/// </summary>
/// <remarks>
/// IMAP commands that contain literal strings are broken up into multiple parts
/// in case the IMAP server does not support the LITERAL+ extension. These parts
/// are then sent individually as we receive "+" responses from the server.
/// </remarks>
class ImapCommandPart
{
public readonly byte[] Command;
public readonly ImapLiteral Literal;
public readonly bool WaitForContinuation;
public ImapCommandPart (byte[] command, ImapLiteral literal, bool wait = true)
{
WaitForContinuation = wait;
Command = command;
Literal = literal;
}
}
/// <summary>
/// An IMAP command.
/// </summary>
class ImapCommand
{
static readonly byte[] UTF8LiteralTokenPrefix = Encoding.ASCII.GetBytes ("UTF8 (~{");
static readonly byte[] LiteralTokenSuffix = { (byte) '}', (byte) '\r', (byte) '\n' };
static readonly byte[] Nil = { (byte) 'N', (byte) 'I', (byte) 'L' };
static readonly byte[] NewLine = { (byte) '\r', (byte) '\n' };
static readonly byte[] LiteralTokenPrefix = { (byte) '{' };
public Dictionary<string, ImapUntaggedHandler> UntaggedHandlers { get; private set; }
public ImapContinuationHandler ContinuationHandler { get; set; }
public CancellationToken CancellationToken { get; private set; }
public ImapCommandStatus Status { get; internal set; }
public ImapCommandResponse Response { get; internal set; }
public ITransferProgress Progress { get; internal set; }
public Exception Exception { get; internal set; }
public readonly List<ImapResponseCode> RespCodes;
public string ResponseText { get; internal set; }
public ImapFolder Folder { get; private set; }
public object UserData { get; internal set; }
public bool ListReturnsSubscribed { get; internal set; }
public bool Logout { get; private set; }
public bool Lsub { get; internal set; }
public string Tag { get; private set; }
public bool Bye { get; internal set; }
readonly List<ImapCommandPart> parts = new List<ImapCommandPart> ();
readonly ImapEngine Engine;
long totalSize, nwritten;
int current;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>.
/// </remarks>
/// <param name="engine">The IMAP engine that will be sending the command.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="folder">The IMAP folder that the command operates on.</param>
/// <param name="options">The formatting options.</param>
/// <param name="format">The command format.</param>
/// <param name="args">The command arguments.</param>
public ImapCommand (ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, FormatOptions options, string format, params object[] args)
{
UntaggedHandlers = new Dictionary<string, ImapUntaggedHandler> (StringComparer.OrdinalIgnoreCase);
Logout = format.Equals ("LOGOUT\r\n", StringComparison.Ordinal);
RespCodes = new List<ImapResponseCode> ();
CancellationToken = cancellationToken;
Response = ImapCommandResponse.None;
Status = ImapCommandStatus.Created;
Engine = engine;
Folder = folder;
using (var builder = new MemoryStream ()) {
byte[] buf, utf8 = new byte[8];
int argc = 0;
string str;
for (int i = 0; i < format.Length; i++) {
if (format[i] == '%') {
switch (format[++i]) {
case '%': // a literal %
builder.WriteByte ((byte) '%');
break;
case 'd': // an integer
str = ((int) args[argc++]).ToString (CultureInfo.InvariantCulture);
buf = Encoding.ASCII.GetBytes (str);
builder.Write (buf, 0, buf.Length);
break;
case 'u': // an unsigned integer
str = ((uint) args[argc++]).ToString (CultureInfo.InvariantCulture);
buf = Encoding.ASCII.GetBytes (str);
builder.Write (buf, 0, buf.Length);
break;
case 's':
str = (string) args[argc++];
buf = Encoding.ASCII.GetBytes (str);
builder.Write (buf, 0, buf.Length);
break;
case 'F': // an ImapFolder
var utf7 = ((ImapFolder) args[argc++]).EncodedName;
AppendString (options, true, builder, utf7);
break;
case 'L': // a MimeMessage or a byte[]
var arg = args[argc++];
ImapLiteral literal;
byte[] prefix;
if (arg is MimeMessage message) {
prefix = options.International ? UTF8LiteralTokenPrefix : LiteralTokenPrefix;
literal = new ImapLiteral (options, message, UpdateProgress);
} else {
literal = new ImapLiteral (options, (byte[]) arg);
prefix = LiteralTokenPrefix;
}
var length = literal.Length;
bool wait = true;
builder.Write (prefix, 0, prefix.Length);
buf = Encoding.ASCII.GetBytes (length.ToString (CultureInfo.InvariantCulture));
builder.Write (buf, 0, buf.Length);
if (CanUseNonSynchronizedLiteral (Engine, length)) {
builder.WriteByte ((byte) '+');
wait = false;
}
builder.Write (LiteralTokenSuffix, 0, LiteralTokenSuffix.Length);
totalSize += length;
parts.Add (new ImapCommandPart (builder.ToArray (), literal, wait));
builder.SetLength (0);
if (prefix == UTF8LiteralTokenPrefix)
builder.WriteByte ((byte) ')');
break;
case 'S': // a string which may need to be quoted or made into a literal
AppendString (options, true, builder, (string) args[argc++]);
break;
case 'Q': // similar to %S but string must be quoted at a minimum
AppendString (options, false, builder, (string) args[argc++]);
break;
default:
throw new FormatException ();
}
} else if (format[i] < 128) {
builder.WriteByte ((byte) format[i]);
} else {
int nchars = char.IsSurrogate (format[i]) ? 2 : 1;
int nbytes = Encoding.UTF8.GetBytes (format, i, nchars, utf8, 0);
builder.Write (utf8, 0, nbytes);
i += nchars - 1;
}
}
parts.Add (new ImapCommandPart (builder.ToArray (), null));
}
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommand"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapCommand"/>.
/// </remarks>
/// <param name="engine">The IMAP engine that will be sending the command.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="folder">The IMAP folder that the command operates on.</param>
/// <param name="format">The command format.</param>
/// <param name="args">The command arguments.</param>
public ImapCommand (ImapEngine engine, CancellationToken cancellationToken, ImapFolder folder, string format, params object[] args)
: this (engine, cancellationToken, folder, FormatOptions.Default, format, args)
{
}
internal static int EstimateCommandLength (ImapEngine engine, FormatOptions options, string format, params object[] args)
{
const int EstimatedTagLength = 10;
var eoln = false;
int length = 0;
int argc = 0;
string str;
for (int i = 0; i < format.Length; i++) {
if (format[i] == '%') {
switch (format[++i]) {
case '%': // a literal %
length++;
break;
case 'd': // an integer
str = ((int) args[argc++]).ToString (CultureInfo.InvariantCulture);
length += str.Length;
break;
case 'u': // an unsigned integer
str = ((uint) args[argc++]).ToString (CultureInfo.InvariantCulture);
length += str.Length;
break;
case 's':
str = (string) args[argc++];
length += str.Length;
break;
case 'F': // an ImapFolder
var utf7 = ((ImapFolder) args[argc++]).EncodedName;
length += EstimateStringLength (engine, options, true, utf7, out eoln);
break;
case 'L': // a MimeMessage or a byte[]
var arg = args[argc++];
byte[] prefix;
long len;
if (arg is MimeMessage message) {
prefix = options.International ? UTF8LiteralTokenPrefix : LiteralTokenPrefix;
var literal = new ImapLiteral (options, message, null);
len = literal.Length;
} else {
len = ((byte[]) arg).Length;
prefix = LiteralTokenPrefix;
}
length += prefix.Length;
length += Encoding.ASCII.GetByteCount (len.ToString (CultureInfo.InvariantCulture));
if (CanUseNonSynchronizedLiteral (engine, len))
length++;
length += LiteralTokenSuffix.Length;
if (prefix == UTF8LiteralTokenPrefix)
length++;
eoln = true;
break;
case 'S': // a string which may need to be quoted or made into a literal
length += EstimateStringLength (engine, options, true, (string) args[argc++], out eoln);
break;
case 'Q': // similar to %S but string must be quoted at a minimum
length += EstimateStringLength (engine, options, false, (string) args[argc++], out eoln);
break;
default:
throw new FormatException ();
}
if (eoln)
break;
} else {
length++;
}
}
return length + EstimatedTagLength;
}
internal static int EstimateCommandLength (ImapEngine engine, string format, params object[] args)
{
return EstimateCommandLength (engine, FormatOptions.Default, format, args);
}
void UpdateProgress (int n)
{
nwritten += n;
if (Progress != null)
Progress.Report (nwritten, totalSize);
}
static bool IsAtom (char c)
{
return c < 128 && !char.IsControl (c) && "(){ \t%*\\\"]".IndexOf (c) == -1;
}
static bool IsQuotedSafe (ImapEngine engine, char c)
{
return (c < 128 || engine.UTF8Enabled) && !char.IsControl (c);
}
internal static ImapStringType GetStringType (ImapEngine engine, string value, bool allowAtom)
{
var type = allowAtom ? ImapStringType.Atom : ImapStringType.QString;
if (value == null)
return ImapStringType.Nil;
if (value.Length == 0)
return ImapStringType.QString;
for (int i = 0; i < value.Length; i++) {
if (!IsAtom (value[i])) {
if (!IsQuotedSafe (engine, value[i]))
return ImapStringType.Literal;
type = ImapStringType.QString;
}
}
return type;
}
static bool CanUseNonSynchronizedLiteral (ImapEngine engine, long length)
{
return (engine.Capabilities & ImapCapabilities.LiteralPlus) != 0 ||
(length <= 4096 && (engine.Capabilities & ImapCapabilities.LiteralMinus) != 0);
}
static int EstimateStringLength (ImapEngine engine, FormatOptions options, bool allowAtom, string value, out bool eoln)
{
eoln = false;
switch (GetStringType (engine, value, allowAtom)) {
case ImapStringType.Literal:
var literal = Encoding.UTF8.GetByteCount (value);
var plus = CanUseNonSynchronizedLiteral (engine, literal);
int length = "{}\r\n".Length;
length += literal.ToString (CultureInfo.InvariantCulture).Length;
if (plus)
length++;
eoln = true;
return length++;
case ImapStringType.QString:
return Encoding.UTF8.GetByteCount (MimeUtils.Quote (value));
case ImapStringType.Nil:
return Nil.Length;
default:
return value.Length;
}
}
void AppendString (FormatOptions options, bool allowAtom, MemoryStream builder, string value)
{
byte[] buf;
switch (GetStringType (Engine, value, allowAtom)) {
case ImapStringType.Literal:
var literal = Encoding.UTF8.GetBytes (value);
var plus = CanUseNonSynchronizedLiteral (Engine, literal.Length);
var length = literal.Length.ToString (CultureInfo.InvariantCulture);
buf = Encoding.ASCII.GetBytes (length);
builder.WriteByte ((byte) '{');
builder.Write (buf, 0, buf.Length);
if (plus)
builder.WriteByte ((byte) '+');
builder.WriteByte ((byte) '}');
builder.WriteByte ((byte) '\r');
builder.WriteByte ((byte) '\n');
if (plus) {
builder.Write (literal, 0, literal.Length);
} else {
parts.Add (new ImapCommandPart (builder.ToArray (), new ImapLiteral (options, literal)));
builder.SetLength (0);
}
break;
case ImapStringType.QString:
buf = Encoding.UTF8.GetBytes (MimeUtils.Quote (value));
builder.Write (buf, 0, buf.Length);
break;
case ImapStringType.Atom:
buf = Encoding.UTF8.GetBytes (value);
builder.Write (buf, 0, buf.Length);
break;
case ImapStringType.Nil:
builder.Write (Nil, 0, Nil.Length);
break;
}
}
/// <summary>
/// Registers the untagged handler for the specified atom token.
/// </summary>
/// <param name="atom">The atom token.</param>
/// <param name="handler">The handler.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="atom"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="handler"/> is <c>null</c>.</para>
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Untagged handlers must be registered before the command has been queued.
/// </exception>
public void RegisterUntaggedHandler (string atom, ImapUntaggedHandler handler)
{
if (atom == null)
throw new ArgumentNullException (nameof (atom));
if (handler == null)
throw new ArgumentNullException (nameof (handler));
if (Status != ImapCommandStatus.Created)
throw new InvalidOperationException ("Untagged handlers must be registered before the command has been queued.");
UntaggedHandlers.Add (atom, handler);
}
/// <summary>
/// Sends the next part of the command to the server.
/// </summary>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="ImapProtocolException">
/// An IMAP protocol error occurred.
/// </exception>
public async Task<bool> StepAsync (bool doAsync)
{
var supportsLiteralPlus = (Engine.Capabilities & ImapCapabilities.LiteralPlus) != 0;
var idle = UserData as ImapIdleContext;
var result = ImapCommandResponse.None;
ImapToken token;
// construct and write the command tag if this is the initial state
if (current == 0) {
Tag = string.Format (CultureInfo.InvariantCulture, "{0}{1:D8}", Engine.TagPrefix, Engine.Tag++);
var buf = Encoding.ASCII.GetBytes (Tag + " ");
if (doAsync)
await Engine.Stream.WriteAsync (buf, 0, buf.Length, CancellationToken).ConfigureAwait (false);
else
Engine.Stream.Write (buf, 0, buf.Length, CancellationToken);
}
do {
var command = parts[current].Command;
if (doAsync)
await Engine.Stream.WriteAsync (command, 0, command.Length, CancellationToken).ConfigureAwait (false);
else
Engine.Stream.Write (command, 0, command.Length, CancellationToken);
// if the server doesn't support LITERAL+ (or LITERAL-), we'll need to wait
// for a "+" response before writing out the any literals...
if (parts[current].WaitForContinuation)
break;
// otherwise, we can write out any and all literal tokens we have...
await parts[current].Literal.WriteToAsync (Engine.Stream, doAsync, CancellationToken).ConfigureAwait (false);
if (current + 1 >= parts.Count)
break;
current++;
} while (true);
if (doAsync)
await Engine.Stream.FlushAsync (CancellationToken).ConfigureAwait (false);
else
Engine.Stream.Flush (CancellationToken);
// now we need to read the response...
do {
if (Engine.State == ImapEngineState.Idle) {
int timeout = Timeout.Infinite;
if (Engine.Stream.CanTimeout) {
timeout = Engine.Stream.ReadTimeout;
Engine.Stream.ReadTimeout = Timeout.Infinite;
}
try {
token = await Engine.ReadTokenAsync (doAsync, CancellationToken).ConfigureAwait (false);
} finally {
if (Engine.Stream.IsConnected && Engine.Stream.CanTimeout)
Engine.Stream.ReadTimeout = timeout;
}
} else {
token = await Engine.ReadTokenAsync (doAsync, CancellationToken).ConfigureAwait (false);
}
if (token.Type == ImapTokenType.Atom && token.Value.ToString () == "+") {
// we've gotten a continuation response from the server
var text = (await Engine.ReadLineAsync (doAsync, CancellationToken).ConfigureAwait (false)).Trim ();
// if we've got a Literal pending, the '+' means we can send it now...
if (!supportsLiteralPlus && parts[current].Literal != null) {
await parts[current].Literal.WriteToAsync (Engine.Stream, doAsync, CancellationToken).ConfigureAwait (false);
break;
}
if (ContinuationHandler != null) {
await ContinuationHandler (Engine, this, text, doAsync).ConfigureAwait (false);
} else if (doAsync) {
await Engine.Stream.WriteAsync (NewLine, 0, NewLine.Length, CancellationToken).ConfigureAwait (false);
await Engine.Stream.FlushAsync (CancellationToken).ConfigureAwait (false);
} else {
Engine.Stream.Write (NewLine, 0, NewLine.Length, CancellationToken);
Engine.Stream.Flush (CancellationToken);
}
} else if (token.Type == ImapTokenType.Asterisk) {
// we got an untagged response, let the engine handle this...
await Engine.ProcessUntaggedResponseAsync (doAsync, CancellationToken).ConfigureAwait (false);
} else if (token.Type == ImapTokenType.Atom && (string) token.Value == Tag) {
// the next token should be "OK", "NO", or "BAD"
token = await Engine.ReadTokenAsync (doAsync, CancellationToken).ConfigureAwait (false);
ImapEngine.AssertToken (token, ImapTokenType.Atom, "Syntax error in tagged response. Unexpected token: {0}", token);
string atom = (string) token.Value;
switch (atom) {
case "BAD": result = ImapCommandResponse.Bad; break;
case "OK": result = ImapCommandResponse.Ok; break;
case "NO": result = ImapCommandResponse.No; break;
default: throw ImapEngine.UnexpectedToken ("Syntax error in tagged response. Unexpected token: {0}", token);
}
token = await Engine.ReadTokenAsync (doAsync, CancellationToken).ConfigureAwait (false);
if (token.Type == ImapTokenType.OpenBracket) {
var code = await Engine.ParseResponseCodeAsync (true, doAsync, CancellationToken).ConfigureAwait (false);
RespCodes.Add (code);
break;
}
if (token.Type != ImapTokenType.Eoln) {
// consume the rest of the line...
var line = await Engine.ReadLineAsync (doAsync, CancellationToken).ConfigureAwait (false);
ResponseText = (((string) token.Value) + line).TrimEnd ();
break;
}
} else if (token.Type == ImapTokenType.OpenBracket) {
// Note: this is a work-around for broken IMAP servers like Office365.com that
// return RESP-CODES that are not preceded by "* OK " such as the example in
// issue #115 (https://github.com/jstedfast/MailKit/issues/115).
var code = await Engine.ParseResponseCodeAsync (false, doAsync, CancellationToken).ConfigureAwait (false);
RespCodes.Add (code);
} else {
// no clue what we got...
throw ImapEngine.UnexpectedToken ("Syntax error in response. Unexpected token: {0}", token);
}
} while (Status == ImapCommandStatus.Active);
if (Status == ImapCommandStatus.Active) {
current++;
if (current >= parts.Count || result != ImapCommandResponse.None) {
Status = ImapCommandStatus.Complete;
Response = result;
return false;
}
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,190 @@
//
// ImapCommandException.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;
#if SERIALIZABLE
using System.Security;
using System.Runtime.Serialization;
#endif
namespace MailKit.Net.Imap {
/// <summary>
/// An exception that is thrown when an IMAP command returns NO or BAD.
/// </summary>
/// <remarks>
/// The exception that is thrown when an IMAP command fails. Unlike a <see cref="ImapProtocolException"/>,
/// a <see cref="ImapCommandException"/> does not require the <see cref="ImapClient"/> to be reconnected.
/// </remarks>
#if SERIALIZABLE
[Serializable]
#endif
public class ImapCommandException : CommandException
{
#if SERIALIZABLE
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapCommandException"/> from the serialized data.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
[SecuritySafeCritical]
protected ImapCommandException (SerializationInfo info, StreamingContext context) : base (info, context)
{
Response = (ImapCommandResponse) info.GetValue ("Response", typeof (ImapCommandResponse));
ResponseText = info.GetString ("ResponseText");
}
#endif
/// <summary>
/// Create a new <see cref="ImapCommandException"/> based on the specified command name and <see cref="ImapCommand"/> state.
/// </summary>
/// <remarks>
/// Create a new <see cref="ImapCommandException"/> based on the specified command name and <see cref="ImapCommand"/> state.
/// </remarks>
/// <returns>A new command exception.</returns>
/// <param name="command">The command name.</param>
/// <param name="ic">The command state.</param>
internal static ImapCommandException Create (string command, ImapCommand ic)
{
var result = ic.Response.ToString ().ToUpperInvariant ();
string message, reason = null;
if (string.IsNullOrEmpty (ic.ResponseText)) {
for (int i = ic.RespCodes.Count - 1; i >= 0; i--) {
if (ic.RespCodes[i].IsError && !string.IsNullOrEmpty (ic.RespCodes[i].Message)) {
reason = ic.RespCodes[i].Message;
break;
}
}
} else {
reason = ic.ResponseText;
}
if (!string.IsNullOrEmpty (reason))
message = string.Format ("The IMAP server replied to the '{0}' command with a '{1}' response: {2}", command, result, reason);
else
message = string.Format ("The IMAP server replied to the '{0}' command with a '{1}' response.", command, result);
return ic.Exception != null ? new ImapCommandException (ic.Response, reason, message, ic.Exception) : new ImapCommandException (ic.Response, reason, message);
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapCommandException"/>.
/// </remarks>
/// <param name="response">The IMAP command response.</param>
/// <param name="message">The error message.</param>
/// <param name="responseText">The human-readable response text.</param>
/// <param name="innerException">The inner exception.</param>
public ImapCommandException (ImapCommandResponse response, string responseText, string message, Exception innerException) : base (message, innerException)
{
ResponseText = responseText;
Response = response;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapCommandException"/>.
/// </remarks>
/// <param name="response">The IMAP command response.</param>
/// <param name="responseText">The human-readable response text.</param>
/// <param name="message">The error message.</param>
public ImapCommandException (ImapCommandResponse response, string responseText, string message) : base (message)
{
ResponseText = responseText;
Response = response;
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapCommandException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapCommandException"/>.
/// </remarks>
/// <param name="response">The IMAP command response.</param>
/// <param name="responseText">The human-readable response text.</param>
public ImapCommandException (ImapCommandResponse response, string responseText)
{
ResponseText = responseText;
Response = response;
}
/// <summary>
/// Gets the IMAP command response.
/// </summary>
/// <remarks>
/// Gets the IMAP command response.
/// </remarks>
/// <value>The IMAP command response.</value>
public ImapCommandResponse Response {
get; private set;
}
/// <summary>
/// Gets the human-readable IMAP command response text.
/// </summary>
/// <remarks>
/// Gets the human-readable IMAP command response text.
/// </remarks>
/// <value>The response text.</value>
public string ResponseText {
get; private set;
}
#if SERIALIZABLE
/// <summary>
/// When overridden in a derived class, sets the <see cref="System.Runtime.Serialization.SerializationInfo"/>
/// with information about the exception.
/// </summary>
/// <remarks>
/// Serializes the state of the <see cref="FolderNotFoundException"/>.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
[SecurityCritical]
public override void GetObjectData (SerializationInfo info, StreamingContext context)
{
base.GetObjectData (info, context);
info.AddValue ("Response", Response, typeof (ImapCommandResponse));
info.AddValue ("ResponseText", ResponseText);
}
#endif
}
}

View File

@ -0,0 +1,55 @@
//
// ImapCommandResult.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.
//
namespace MailKit.Net.Imap {
/// <summary>
/// An enumeration of possible IMAP command responses.
/// </summary>
/// <remarks>
/// An enumeration of possible IMAP command responses.
/// </remarks>
public enum ImapCommandResponse {
/// <summary>
/// No IMAP command response yet.
/// </summary>
None,
/// <summary>
/// The command resulted in an "OK" response.
/// </summary>
Ok,
/// <summary>
/// The command resulted in a "NO" response.
/// </summary>
No,
/// <summary>
/// The command resulted in a "BAD" response.
/// </summary>
Bad
}
}

View File

@ -0,0 +1,155 @@
//
// ImapEncoding.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.Text;
namespace MailKit.Net.Imap {
static class ImapEncoding
{
const string utf7_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
static readonly byte[] utf7_rank = {
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255, 62, 63,255,255,255,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255,
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
};
public static string Decode (string text)
{
var decoded = new StringBuilder ();
bool shifted = false;
int bits = 0, v = 0;
int index = 0;
char c;
while (index < text.Length) {
c = text[index++];
if (shifted) {
if (c == '-') {
// shifted back out of modified UTF-7
shifted = false;
bits = v = 0;
} else if (c > 127) {
// invalid UTF-7
return text;
} else {
byte rank = utf7_rank[(byte) c];
if (rank == 0xff) {
// invalid UTF-7
return text;
}
v = (v << 6) | rank;
bits += 6;
if (bits >= 16) {
char u = (char) ((v >> (bits - 16)) & 0xffff);
decoded.Append (u);
bits -= 16;
}
}
} else if (c == '&' && index < text.Length) {
if (text[index] == '-') {
decoded.Append ('&');
index++;
} else {
// shifted into modified UTF-7
shifted = true;
}
} else {
decoded.Append (c);
}
}
return decoded.ToString ();
}
static void Utf7ShiftOut (StringBuilder output, int u, int bits)
{
if (bits > 0) {
int x = (u << (6 - bits)) & 0x3f;
output.Append (utf7_alphabet[x]);
}
output.Append ('-');
}
public static string Encode (string text)
{
var encoded = new StringBuilder ();
bool shifted = false;
int bits = 0, u = 0;
for (int index = 0; index < text.Length; index++) {
char c = text[index];
if (c >= 0x20 && c < 0x7f) {
// characters with octet values 0x20-0x25 and 0x27-0x7e
// represent themselves while 0x26 ("&") is represented
// by the two-octet sequence "&-"
if (shifted) {
Utf7ShiftOut (encoded, u, bits);
shifted = false;
bits = 0;
}
if (c == 0x26)
encoded.Append ("&-");
else
encoded.Append (c);
} else {
// base64 encode
if (!shifted) {
encoded.Append ('&');
shifted = true;
}
u = (u << 16) | (c & 0xffff);
bits += 16;
while (bits >= 6) {
int x = (u >> (bits - 6)) & 0x3f;
encoded.Append (utf7_alphabet[x]);
bits -= 6;
}
}
}
if (shifted)
Utf7ShiftOut (encoded, u, bits);
return encoded.ToString ();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,692 @@
//
// ImapFolderFetch.cs
//
// Authors: Steffen Kieß <s-kiess@web.de>
// 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.Text;
using System.Collections.Generic;
using MimeKit;
namespace MailKit.Net.Imap {
/// <summary>
/// An IMAP event group used with the NOTIFY command.
/// </summary>
/// <remarks>
/// An IMAP event group used with the NOTIFY command.
/// </remarks>
public sealed class ImapEventGroup
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEventGroup"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEventGroup"/> class.
/// </remarks>
/// <param name="mailboxFilter">The mailbox filter.</param>
/// <param name="events">The list of IMAP events.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="mailboxFilter"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="events"/> is <c>null</c>.</para>
/// </exception>
public ImapEventGroup (ImapMailboxFilter mailboxFilter, IList<ImapEvent> events)
{
if (mailboxFilter == null)
throw new ArgumentNullException (nameof (mailboxFilter));
if (events == null)
throw new ArgumentNullException (nameof (events));
MailboxFilter = mailboxFilter;
Events = events;
}
/// <summary>
/// Get the mailbox filter.
/// </summary>
/// <remarks>
/// Gets the mailbox filter.
/// </remarks>
/// <value>The mailbox filter.</value>
public ImapMailboxFilter MailboxFilter {
get; private set;
}
/// <summary>
/// Get the list of IMAP events.
/// </summary>
/// <remarks>
/// Gets the list of IMAP events.
/// </remarks>
/// <value>The events.</value>
public IList<ImapEvent> Events {
get; private set;
}
/// <summary>
/// Format the IMAP NOTIFY command for this particular IMAP event group.
/// </summary>
/// <remarks>
/// Formats the IMAP NOTIFY command for this particular IMAP event group.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="command">The IMAP command builder.</param>
/// <param name="args">The IMAP command argument builder.</param>
/// <param name="notifySelectedNewExpunge">Gets set to <c>true</c> if the NOTIFY command requests the MessageNew or
/// MessageExpunged events for a SELECTED or SELECTED-DELAYED mailbox filter; otherwise it is left unchanged.</param>
internal void Format (ImapEngine engine, StringBuilder command, IList<object> args, ref bool notifySelectedNewExpunge)
{
bool isSelectedFilter = MailboxFilter == ImapMailboxFilter.Selected || MailboxFilter == ImapMailboxFilter.SelectedDelayed;
command.Append ("(");
MailboxFilter.Format (engine, command, args);
command.Append (" ");
if (Events.Count > 0) {
var haveAnnotationChange = false;
var haveMessageExpunge = false;
var haveMessageNew = false;
var haveFlagChange = false;
command.Append ("(");
for (int i = 0; i < Events.Count; i++) {
var @event = Events[i];
if (isSelectedFilter && !@event.IsMessageEvent)
throw new InvalidOperationException ("Only message events may be specified when SELECTED or SELECTED-DELAYED is used.");
if (@event is ImapEvent.MessageNew)
haveMessageNew = true;
else if (@event == ImapEvent.MessageExpunge)
haveMessageExpunge = true;
else if (@event == ImapEvent.FlagChange)
haveFlagChange = true;
else if (@event == ImapEvent.AnnotationChange)
haveAnnotationChange = true;
if (i > 0)
command.Append (" ");
@event.Format (engine, command, args, isSelectedFilter);
}
command.Append (")");
// https://tools.ietf.org/html/rfc5465#section-5
if ((haveMessageNew && !haveMessageExpunge) || (!haveMessageNew && haveMessageExpunge))
throw new InvalidOperationException ("If MessageNew or MessageExpunge is specified, both must be specified.");
if ((haveFlagChange || haveAnnotationChange) && (!haveMessageNew || !haveMessageExpunge))
throw new InvalidOperationException ("If FlagChange and/or AnnotationChange are specified, MessageNew and MessageExpunge must also be specified.");
notifySelectedNewExpunge = (haveMessageNew || haveMessageExpunge) && MailboxFilter == ImapMailboxFilter.Selected;
} else {
command.Append ("NONE");
}
command.Append (")");
}
}
/// <summary>
/// An IMAP mailbox filter for use with the NOTIFY command.
/// </summary>
/// <remarks>
/// An IMAP mailbox filter for use with the NOTIFY command.
/// </remarks>
public class ImapMailboxFilter
{
/// <summary>
/// An IMAP mailbox filter specifying that the client wants immediate notifications for
/// the currently selected folder.
/// </summary>
/// <remarks>
/// The <c>SELECTED</c> mailbox specifier requires the server to send immediate
/// notifications for the currently selected mailbox about all specified
/// message events.
/// </remarks>
public static readonly ImapMailboxFilter Selected = new ImapMailboxFilter ("SELECTED");
/// <summary>
/// An IMAP mailbox filter specifying the currently selected folder but delays notifications
/// until a command has been issued.
/// </summary>
/// <remarks>
/// The <c>SELECTED-DELAYED</c> mailbox specifier requires the server to delay a
/// <see cref="ImapEvent.MessageExpunge"/> event until the client issues a command that allows
/// returning information about expunged messages (see
/// <a href="https://tools.ietf.org/html/rfc3501#section-7.4.1">Section 7.4.1 of RFC3501]</a>
/// for more details), for example, till a <c>NOOP</c> or an <c>IDLE</c> command has been issued.
/// When <c>SELECTED-DELAYED</c> is specified, the server MAY also delay returning other message
/// events until the client issues one of the commands specified above, or it MAY return them
/// immediately.
/// </remarks>
public static readonly ImapMailboxFilter SelectedDelayed = new ImapMailboxFilter ("SELECTED-DELAYED");
/// <summary>
/// An IMAP mailbox filter specifying the currently selected folder.
/// </summary>
/// <remarks>
/// <para>The <c>INBOXES</c> mailbox specifier refers to all selectable mailboxes in the user's
/// personal namespace(s) to which messages may be delivered by a Message Delivery Agent (MDA).
/// </para>
/// <para>If the IMAP server cannot easily compute this set, it MUST treat <see cref="Inboxes"/>
/// as equivalent to <see cref="Personal"/>.</para>
/// </remarks>
public static readonly ImapMailboxFilter Inboxes = new ImapMailboxFilter ("INBOXES");
/// <summary>
/// An IMAP mailbox filter specifying all selectable folders within the user's personal namespace.
/// </summary>
/// <remarks>
/// The <c>PERSONAL</c> mailbox specifier refers to all selectable folders within the user's personal namespace.
/// </remarks>
public static readonly ImapMailboxFilter Personal = new ImapMailboxFilter ("PERSONAL");
/// <summary>
/// An IMAP mailbox filter that refers to all subscribed folders.
/// </summary>
/// <remarks>
/// <para>The <c>SUBSCRIBED</c> mailbox specifier refers to all folders subscribed to by the user.</para>
/// <para>If the subscription list changes, the server MUST reevaluate the list.</para>
/// </remarks>
public static readonly ImapMailboxFilter Subscribed = new ImapMailboxFilter ("SUBSCRIBED");
/// <summary>
/// An IMAP mailbox filter that specifies a list of folders to receive notifications about.
/// </summary>
/// <remarks>
/// An IMAP mailbox filter that specifies a list of folders to receive notifications about.
/// </remarks>
public class Mailboxes : ImapMailboxFilter
{
readonly ImapFolder[] folders;
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Mailboxes"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Mailboxes"/> class.
/// </remarks>
/// <param name="folders">The list of folders to watch for events.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folders"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para>The list of <paramref name="folders"/> is empty.</para>
/// <para>-or-</para>
/// <para>The list of <paramref name="folders"/> contains folders that are not of
/// type <see cref="ImapFolder"/>.</para>
/// </exception>
public Mailboxes (IList<IMailFolder> folders) : this ("MAILBOXES", folders)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Mailboxes"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Mailboxes"/> class.
/// </remarks>
/// <param name="folders">The list of folders to watch for events.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folders"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para>The list of <paramref name="folders"/> is empty.</para>
/// <para>-or-</para>
/// <para>The list of <paramref name="folders"/> contains folders that are not of
/// type <see cref="ImapFolder"/>.</para>
/// </exception>
public Mailboxes (params IMailFolder[] folders) : this ("MAILBOXES", folders)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Mailboxes"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Mailboxes"/> class.
/// </remarks>
/// <param name="name">The name of the mailbox filter.</param>
/// <param name="folders">The list of folders to watch for events.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folders"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para>The list of <paramref name="folders"/> is empty.</para>
/// <para>-or-</para>
/// <para>The list of <paramref name="folders"/> contains folders that are not of
/// type <see cref="ImapFolder"/>.</para>
/// </exception>
internal Mailboxes (string name, IList<IMailFolder> folders) : base (name)
{
if (folders == null)
throw new ArgumentNullException (nameof (folders));
if (folders.Count == 0)
throw new ArgumentException ("Must supply at least one folder.", nameof (folders));
this.folders = new ImapFolder[folders.Count];
for (int i = 0; i < folders.Count; i++) {
if (!(folders[i] is ImapFolder folder))
throw new ArgumentException ("All folders must be ImapFolders.", nameof (folders));
this.folders[i] = folder;
}
}
/// <summary>
/// Format the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </summary>
/// <remarks>
/// Formats the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="command">The IMAP command builder.</param>
/// <param name="args">The IMAP command argument builder.</param>
internal override void Format (ImapEngine engine, StringBuilder command, IList<object> args)
{
command.Append (Name);
command.Append (' ');
// FIXME: should we verify that each ImapFolder belongs to this ImapEngine?
if (folders.Length == 1) {
command.Append ("%F");
args.Add (folders[0]);
} else {
command.Append ("(");
for (int i = 0; i < folders.Length; i++) {
if (i > 0)
command.Append (" ");
command.Append ("%F");
args.Add (folders[i]);
}
command.Append (")");
}
}
}
/// <summary>
/// An IMAP mailbox filter that specifies a list of folder subtrees to get notifications about.
/// </summary>
/// <remarks>
/// <para>The client will receive notifications for each specified folder plus all selectable
/// folders that are subordinate to any of the specified folders.</para>
/// </remarks>
public class Subtree : Mailboxes
{
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Subtree"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Subtree"/> class.
/// </remarks>
/// <param name="folders">The list of folders to watch for events.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folders"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para>The list of <paramref name="folders"/> is empty.</para>
/// <para>-or-</para>
/// <para>The list of <paramref name="folders"/> contains folders that are not of
/// type <see cref="ImapFolder"/>.</para>
/// </exception>
public Subtree (IList<IMailFolder> folders) : base ("SUBTREE", folders)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Subtree"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter.Subtree"/> class.
/// </remarks>
/// <param name="folders">The list of folders to watch for events.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="folders"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <para>The list of <paramref name="folders"/> is empty.</para>
/// <para>-or-</para>
/// <para>The list of <paramref name="folders"/> contains folders that are not of
/// type <see cref="ImapFolder"/>.</para>
/// </exception>
public Subtree (params IMailFolder[] folders) : base ("SUBTREE", folders)
{
}
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapMailboxFilter"/> class.
/// </remarks>
/// <param name="name">The name of the mailbox filter.</param>
internal ImapMailboxFilter (string name)
{
Name = name;
}
/// <summary>
/// Get the name of the mailbox filter.
/// </summary>
/// <remarks>
/// Gets the name of the mailbox filter.
/// </remarks>
/// <value>The name.</value>
public string Name { get; private set; }
/// <summary>
/// Format the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </summary>
/// <remarks>
/// Formats the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="command">The IMAP command builder.</param>
/// <param name="args">The IMAP command argument builder.</param>
internal virtual void Format (ImapEngine engine, StringBuilder command, IList<object> args)
{
command.Append (Name);
}
}
/// <summary>
/// An IMAP notification event.
/// </summary>
/// <remarks>
/// An IMAP notification event.
/// </remarks>
public class ImapEvent
{
/// <summary>
/// An IMAP event notification for expunged messages.
/// </summary>
/// <remarks>
/// <para>If the expunged message or messages are in the selected mailbox, the server notifies the client
/// using <see cref="IMailFolder.MessageExpunged"/> (or <see cref="IMailFolder.MessagesVanished"/> if
/// the <a href="https://tools.ietf.org/html/rfc5162">QRESYNC</a> extension has been enabled via
/// <see cref="ImapClient.EnableQuickResync(System.Threading.CancellationToken)"/> or
/// <see cref="ImapClient.EnableQuickResyncAsync(System.Threading.CancellationToken)"/>).</para>
/// <para>If the expunged message or messages are in another mailbox, the <see cref="IMailFolder.UidNext"/>
/// and <see cref="IMailFolder.Count"/> properties will be updated and the appropriate
/// <see cref="IMailFolder.UidNextChanged"/> and <see cref="IMailFolder.CountChanged"/> events will be
/// emitted for the relevant folder. If the <a href="https://tools.ietf.org/html/rfc5162">QRESYNC</a>
/// extension is enabled, the <see cref="IMailFolder.HighestModSeq"/> property will also be updated and
/// the <see cref="IMailFolder.HighestModSeqChanged"/> event will be emitted.</para>
/// <note type="note">if a client requests <see cref="MessageExpunge"/> with the <see cref="ImapMailboxFilter.Selected"/>
/// mailbox specifier, the meaning of a message index can change at any time, so the client cannot use
/// message indexes in commands anymore. The client MUST use API variants that take <see cref="UniqueId"/> or
/// a <see cref="IList{UniqueId}"/>. The meaning of <c>*</c>* can also change when messages are added or expunged.
/// A client wishing to keep using message indexes can either use the <see cref="ImapMailboxFilter.SelectedDelayed"/>
/// mailbox specifier or can avoid using the <see cref="MessageExpunge"/> event entirely.</note>
/// </remarks>
public static readonly ImapEvent MessageExpunge = new ImapEvent ("MessageExpunge", true);
/// <summary>
/// An IMAP event notification for message flag changes.
/// </summary>
/// <remarks>
/// <para>If the <see cref="FlagChange"/> notification arrives for a message located in the currently selected
/// folder, then that folder will emit a <see cref="IMailFolder.MessageFlagsChanged"/> event as well as a
/// <see cref="IMailFolder.MessageSummaryFetched"/> event with an appropriately populated
/// <see cref="IMessageSummary"/>.</para>
/// <para>On the other hand, if the <see cref="FlagChange"/> notification arrives for a message that is not
/// located in the currently selected folder, then the events that are emitted will depend on the
/// <see cref="ImapCapabilities"/> of the IMAP server.</para>
/// <para>If the server supports the <see cref="ImapCapabilities.CondStore"/> capability (or the
/// <see cref="ImapCapabilities.QuickResync"/> capability and the client has enabled it via
/// <see cref="ImapClient.EnableQuickResync(System.Threading.CancellationToken)"/>), then the
/// <see cref="IMailFolder.HighestModSeqChanged"/> event will be emitted as well as the
/// <see cref="IMailFolder.UidValidityChanged"/> event (if the latter has changed). If the number of
/// seen messages has changed, then the <see cref="IMailFolder.UnreadChanged"/> event may also be emitted.</para>
/// <para>If the server does not support either the <see cref="ImapCapabilities.CondStore"/> capability nor
/// the <see cref="ImapCapabilities.QuickResync"/> capability and the client has not enabled the later capability
/// via <see cref="ImapClient.EnableQuickResync(System.Threading.CancellationToken)"/>, then the server may choose
/// only to notify the client of <see cref="IMailFolder.UidValidity"/> changes by emitting the
/// <see cref="IMailFolder.UidValidityChanged"/> event.</para>
/// </remarks>
public static readonly ImapEvent FlagChange = new ImapEvent ("FlagChange", true);
/// <summary>
/// An IMAP event notification for message annotation changes.
/// </summary>
/// <remarks>
/// <para>If the <see cref="AnnotationChange"/> notification arrives for a message located in the currently selected
/// folder, then that folder will emit a <see cref="IMailFolder.AnnotationsChanged"/> event as well as a
/// <see cref="IMailFolder.MessageSummaryFetched"/> event with an appropriately populated
/// <see cref="IMessageSummary"/>.</para>
/// <para>On the other hand, if the <see cref="AnnotationChange"/> notification arrives for a message that is not
/// located in the currently selected folder, then the events that are emitted will depend on the
/// <see cref="ImapCapabilities"/> of the IMAP server.</para>
/// <para>If the server supports the <see cref="ImapCapabilities.CondStore"/> capability (or the
/// <see cref="ImapCapabilities.QuickResync"/> capability and the client has enabled it via
/// <see cref="ImapClient.EnableQuickResync(System.Threading.CancellationToken)"/>), then the
/// <see cref="IMailFolder.HighestModSeqChanged"/> event will be emitted as well as the
/// <see cref="IMailFolder.UidValidityChanged"/> event (if the latter has changed). If the number of
/// seen messages has changed, then the <see cref="IMailFolder.UnreadChanged"/> event may also be emitted.</para>
/// <para>If the server does not support either the <see cref="ImapCapabilities.CondStore"/> capability nor
/// the <see cref="ImapCapabilities.QuickResync"/> capability and the client has not enabled the later capability
/// via <see cref="ImapClient.EnableQuickResync(System.Threading.CancellationToken)"/>, then the server may choose
/// only to notify the client of <see cref="IMailFolder.UidValidity"/> changes by emitting the
/// <see cref="IMailFolder.UidValidityChanged"/> event.</para>
/// </remarks>
public static readonly ImapEvent AnnotationChange = new ImapEvent ("AnnotationChange", true);
/// <summary>
/// AN IMAP event notification for folders that have been created, deleted, or renamed.
/// </summary>
/// <remarks>
/// <para>These notifications are sent if an affected mailbox name was created, deleted, or renamed.</para>
/// <para>As these notifications are received by the client, the apropriate will be emitted:
/// <see cref="MailStore.FolderCreated"/>, <see cref="IMailFolder.Deleted"/>, or
/// <see cref="IMailFolder.Renamed"/>, respectively.</para>
/// <note type="info">If the server supports <see cref="ImapCapabilities.Acl"/>, granting or revocation of the
/// <see cref="AccessRight.LookupFolder"/> right to the current user on the affected folder will also be
/// considered folder creation or deletion, respectively. If a folder is created or deleted, the folder itself
/// and its direct parent (whether it is an existing folder or not) are considered to be affected.</note>
/// </remarks>
public static readonly ImapEvent MailboxName = new ImapEvent ("MailboxName", false);
/// <summary>
/// An IMAP event notification for folders who have had their subscription status changed.
/// </summary>
/// <remarks>
/// <para>This event requests that the server notifies the client of any subscription changes,
/// causing the <see cref="IMailFolder.Subscribed"/> or <see cref="IMailFolder.Unsubscribed"/>
/// events to be emitted accordingly on the affected <see cref="IMailFolder"/>.</para>
/// </remarks>
public static readonly ImapEvent SubscriptionChange = new ImapEvent ("SubscriptionChange", false);
/// <summary>
/// An IMAP event notification for changes to folder metadata.
/// </summary>
/// <remarks>
/// <para>Support for this event type is OPTIONAL unless <see cref="ImapCapabilities.Metadata"/> is supported
/// by the server, in which case support for this event type is REQUIRED.</para>
/// <para>If the server does support this event, then the <see cref="IMailFolder.MetadataChanged"/> event
/// will be emitted whenever metadata changes for any folder included in the <see cref="ImapMailboxFilter"/>.</para>
/// </remarks>
public static readonly ImapEvent MailboxMetadataChange = new ImapEvent ("MailboxMetadataChange", false);
/// <summary>
/// An IMAP event notification for changes to server metadata.
/// </summary>
/// <remarks>
/// <para>Support for this event type is OPTIONAL unless <see cref="ImapCapabilities.Metadata"/> is supported
/// by the server, in which case support for this event type is REQUIRED.</para>
/// <para>If the server does support this event, then the <see cref="IMailStore.MetadataChanged"/> event
/// will be emitted whenever metadata changes.</para>
/// </remarks>
public static readonly ImapEvent ServerMetadataChange = new ImapEvent ("ServerMetadataChange", false);
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent"/> class.
/// </remarks>
/// <param name="name">The name of the IMAP event.</param>
/// <param name="isMessageEvent"><c>true</c> if the event is a message event; otherwise, <c>false</c>.</param>
internal ImapEvent (string name, bool isMessageEvent)
{
IsMessageEvent = isMessageEvent;
Name = name;
}
/// <summary>
/// Get whether or not this <see cref="T:MailKit.Net.Imap.ImapEvent"/> is a message event.
/// </summary>
/// <remarks>
/// Gets whether or not this <see cref="T:MailKit.Net.Imap.ImapEvent"/> is a message event.
/// </remarks>
/// <value><c>true</c> if is message event; otherwise, <c>false</c>.</value>
internal bool IsMessageEvent {
get; private set;
}
/// <summary>
/// Get the name of the IMAP event.
/// </summary>
/// <remarks>
/// Gets the name of the IMAP event.
/// </remarks>
/// <value>The name of the IMAP event.</value>
public string Name {
get; private set;
}
/// <summary>
/// Format the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </summary>
/// <remarks>
/// Formats the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="command">The IMAP command builder.</param>
/// <param name="args">The IMAP command argument builder.</param>
/// <param name="isSelectedFilter"><c>true</c> if the event is being registered for a
/// <see cref="ImapMailboxFilter.Selected"/> or <see cref="ImapMailboxFilter.SelectedDelayed"/>
/// mailbox filter.</param>
internal virtual void Format (ImapEngine engine, StringBuilder command, IList<object> args, bool isSelectedFilter)
{
command.Append (Name);
}
/// <summary>
/// An IMAP event notification for new or appended messages.
/// </summary>
/// <remarks>
/// <para>An IMAP event notification for new or appended messages.</para>
/// <para>If the new or appended message is in the selected folder, the folder will emit the
/// <see cref="IMailFolder.CountChanged"/> event, followed by a
/// <see cref="IMailFolder.MessageSummaryFetched"/> event containing the information requested by the client.</para>
/// <note type="note">These events will not be emitted for any message created by the client on this particular folder
/// as a result of, for example, a call to
/// <see cref="IMailFolder.Append(MimeMessage, MessageFlags, System.Threading.CancellationToken, ITransferProgress)"/>
/// or <see cref="IMailFolder.CopyTo(IList{UniqueId}, IMailFolder, System.Threading.CancellationToken)"/>.</note>
/// </remarks>
public class MessageNew : ImapEvent
{
readonly MessageSummaryItems items;
readonly HashSet<string> headers;
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent.MessageNew"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent.MessageNew"/> class.
/// </remarks>
/// <param name="items">The message summary items to automatically retrieve for new messages.</param>
public MessageNew (MessageSummaryItems items = MessageSummaryItems.None) : base ("MessageNew", true)
{
headers = ImapFolder.EmptyHeaderFields;
this.items = items;
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent.MessageNew"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent.MessageNew"/> class.
/// </remarks>
/// <param name="items">The message summary items to automatically retrieve for new messages.</param>
/// <param name="headers">Additional message headers to retrieve for new messages.</param>
public MessageNew (MessageSummaryItems items, HashSet<HeaderId> headers) : this (items)
{
this.headers = ImapUtils.GetUniqueHeaders (headers);
}
/// <summary>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent.MessageNew"/> class.
/// </summary>
/// <remarks>
/// Initializes a new instance of the <see cref="T:MailKit.Net.Imap.ImapEvent.MessageNew"/> class.
/// </remarks>
/// <param name="items">The message summary items to automatically retrieve for new messages.</param>
/// <param name="headers">Additional message headers to retrieve for new messages.</param>
public MessageNew (MessageSummaryItems items, HashSet<string> headers) : this (items)
{
this.headers = ImapUtils.GetUniqueHeaders (headers);
}
/// <summary>
/// Format the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </summary>
/// <remarks>
/// Formats the IMAP NOTIFY command for this particular IMAP mailbox filter.
/// </remarks>
/// <param name="engine">The IMAP engine.</param>
/// <param name="command">The IMAP command builder.</param>
/// <param name="args">The IMAP command argument builder.</param>
/// <param name="isSelectedFilter"><c>true</c> if the event is being registered for a
/// <see cref="ImapMailboxFilter.Selected"/> or <see cref="ImapMailboxFilter.SelectedDelayed"/>
/// mailbox filter.</param>
internal override void Format (ImapEngine engine, StringBuilder command, IList<object> args, bool isSelectedFilter)
{
command.Append (Name);
if (items == MessageSummaryItems.None && headers.Count == 0)
return;
if (!isSelectedFilter)
throw new InvalidOperationException ("The MessageNew event cannot have any parameters for mailbox filters other than SELECTED and SELECTED-DELAYED.");
var xitems = items;
bool previewText;
command.Append (" ");
command.Append (ImapFolder.FormatSummaryItems (engine, ref xitems, headers, out previewText, isNotify: true));
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,567 @@
//
// ImapFolderAnnotations.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.Text;
using System.Threading;
using System.Globalization;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace MailKit.Net.Imap
{
public partial class ImapFolder
{
async Task<IList<UniqueId>> StoreAsync (IList<UniqueId> uids, ulong? modseq, IList<Annotation> annotations, bool doAsync, CancellationToken cancellationToken)
{
if (uids == null)
throw new ArgumentNullException (nameof (uids));
if (modseq.HasValue && !supportsModSeq)
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
if (annotations == null)
throw new ArgumentNullException (nameof (annotations));
CheckState (true, true);
if (AnnotationAccess == AnnotationAccess.None)
throw new NotSupportedException ("The ImapFolder does not support annotations.");
if (uids.Count == 0 || annotations.Count == 0)
return new UniqueId[0];
var builder = new StringBuilder ("UID STORE %s ");
var values = new List<object> ();
UniqueIdSet unmodified = null;
if (modseq.HasValue)
builder.AppendFormat (CultureInfo.InvariantCulture, "(UNCHANGEDSINCE {0}) ", modseq.Value);
ImapUtils.FormatAnnotations (builder, annotations, values, true);
builder.Append ("\r\n");
var command = builder.ToString ();
var args = values.ToArray ();
foreach (var ic in Engine.QueueCommands (cancellationToken, this, command, uids, args)) {
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
ProcessResponseCodes (ic, null);
if (ic.Response != ImapCommandResponse.Ok)
throw ImapCommandException.Create ("STORE", ic);
ProcessUnmodified (ic, ref unmodified, modseq);
}
if (unmodified == null)
return new UniqueId[0];
return unmodified;
}
/// <summary>
/// Store the annotations for the specified messages.
/// </summary>
/// <remarks>
/// Stores the annotations for the specified messages.
/// </remarks>
/// <param name="uids">The UIDs of the messages.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The <see cref="ImapFolder"/> does not support annotations.
/// </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 void Store (IList<UniqueId> uids, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
StoreAsync (uids, null, annotations, false, cancellationToken).GetAwaiter ().GetResult ();
}
/// <summary>
/// Asynchronously store the annotations for the specified messages.
/// </summary>
/// <remarks>
/// Asynchronously stores the annotations for the specified messages.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="uids">The UIDs of the messages.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The <see cref="ImapFolder"/> does not support annotations.
/// </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 StoreAsync (IList<UniqueId> uids, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
return StoreAsync (uids, null, annotations, true, cancellationToken);
}
/// <summary>
/// Store the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </summary>
/// <remarks>
/// Stores the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </remarks>
/// <returns>The unique IDs of the messages that were not updated.</returns>
/// <param name="uids">The UIDs of the messages.</param>
/// <param name="modseq">The mod-sequence value.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>The <see cref="ImapFolder"/> does not support annotations.</para>
/// <para>-or-</para>
/// <para>The <see cref="ImapFolder"/> does not support mod-sequences.</para>
/// </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<UniqueId> Store (IList<UniqueId> uids, ulong modseq, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
return StoreAsync (uids, modseq, annotations, false, cancellationToken).GetAwaiter ().GetResult ();
}
/// <summary>
/// Asynchronously store the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </summary>
/// <remarks>
/// Asynchronously stores the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </remarks>
/// <returns>The unique IDs of the messages that were not updated.</returns>
/// <param name="uids">The UIDs of the messages.</param>
/// <param name="modseq">The mod-sequence value.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>The <see cref="ImapFolder"/> does not support annotations.</para>
/// <para>-or-</para>
/// <para>The <see cref="ImapFolder"/> does not support mod-sequences.</para>
/// </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<UniqueId>> StoreAsync (IList<UniqueId> uids, ulong modseq, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
return StoreAsync (uids, modseq, annotations, true, cancellationToken);
}
async Task<IList<int>> StoreAsync (IList<int> indexes, ulong? modseq, IList<Annotation> annotations, bool doAsync, CancellationToken cancellationToken)
{
if (indexes == null)
throw new ArgumentNullException (nameof (indexes));
if (modseq.HasValue && !supportsModSeq)
throw new NotSupportedException ("The ImapFolder does not support mod-sequences.");
if (annotations == null)
throw new ArgumentNullException (nameof (annotations));
CheckState (true, true);
if (AnnotationAccess == AnnotationAccess.None)
throw new NotSupportedException ("The ImapFolder does not support annotations.");
if (indexes.Count == 0 || annotations.Count == 0)
return new int[0];
var set = ImapUtils.FormatIndexSet (indexes);
var builder = new StringBuilder ("STORE ");
var values = new List<object> ();
builder.AppendFormat ("{0} ", set);
if (modseq.HasValue)
builder.AppendFormat (CultureInfo.InvariantCulture, "(UNCHANGEDSINCE {0}) ", modseq.Value);
ImapUtils.FormatAnnotations (builder, annotations, values, true);
builder.Append ("\r\n");
var command = builder.ToString ();
var args = values.ToArray ();
var ic = Engine.QueueCommand (cancellationToken, this, command, args);
await Engine.RunAsync (ic, doAsync).ConfigureAwait (false);
ProcessResponseCodes (ic, null);
if (ic.Response != ImapCommandResponse.Ok)
throw ImapCommandException.Create ("STORE", ic);
return GetUnmodified (ic, modseq);
}
/// <summary>
/// Store the annotations for the specified messages.
/// </summary>
/// <remarks>
/// Stores the annotations for the specified messages.
/// </remarks>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The <see cref="ImapFolder"/> does not support annotations.
/// </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 void Store (IList<int> indexes, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
StoreAsync (indexes, null, annotations, false, cancellationToken).GetAwaiter ().GetResult ();
}
/// <summary>
/// Asynchronously store the annotations for the specified messages.
/// </summary>
/// <remarks>
/// Asynchronously stores the annotations for the specified messages.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The <see cref="ImapFolder"/> does not support annotations.
/// </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 StoreAsync (IList<int> indexes, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
return StoreAsync (indexes, null, annotations, true, cancellationToken);
}
/// <summary>
/// Store the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </summary>
/// <remarks>
/// Stores the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </remarks>
/// <returns>The indexes of the messages that were not updated.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="modseq">The mod-sequence value.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>The <see cref="ImapFolder"/> does not support annotations.</para>
/// <para>-or-</para>
/// <para>The <see cref="ImapFolder"/> does not support mod-sequences.</para>
/// </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<int> Store (IList<int> indexes, ulong modseq, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
return StoreAsync (indexes, modseq, annotations, false, cancellationToken).GetAwaiter ().GetResult ();
}
/// <summary>
/// Asynchronously store the annotations for the specified messages only if their mod-sequence value is less than the specified value.
/// </summary>
/// <remarks>
/// Asynchronously stores the annotations for the specified messages only if their mod-sequence value is less than the specified value.s
/// </remarks>
/// <returns>The indexes of the messages that were not updated.</returns>
/// <param name="indexes">The indexes of the messages.</param>
/// <param name="modseq">The mod-sequence value.</param>
/// <param name="annotations">The annotations to store.</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="annotations"/> 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 in read-write mode.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// Cannot store annotations without any properties defined.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// <para>The <see cref="ImapFolder"/> does not support annotations.</para>
/// <para>-or-</para>
/// <para>The <see cref="ImapFolder"/> does not support mod-sequences.</para>
/// </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<int>> StoreAsync (IList<int> indexes, ulong modseq, IList<Annotation> annotations, CancellationToken cancellationToken = default (CancellationToken))
{
return StoreAsync (indexes, modseq, annotations, true, cancellationToken);
}
}
}

View File

@ -0,0 +1,113 @@
//
// ImapFolderInfo.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;
namespace MailKit.Net.Imap {
/// <summary>
/// Constructor arguments for <see cref="ImapFolder"/>.
/// </summary>
/// <remarks>
/// Constructor arguments for <see cref="ImapFolder"/>.
/// </remarks>
public sealed class ImapFolderConstructorArgs
{
internal readonly string EncodedName;
internal readonly ImapEngine Engine;
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapFolderConstructorArgs"/> class.
/// </summary>
/// <param name="engine">The IMAP command engine.</param>
/// <param name="encodedName">The encoded name.</param>
/// <param name="attributes">The attributes.</param>
/// <param name="delim">The directory separator.</param>
internal ImapFolderConstructorArgs (ImapEngine engine, string encodedName, FolderAttributes attributes, char delim) : this ()
{
FullName = engine.DecodeMailboxName (encodedName);
Name = GetBaseName (FullName, delim);
DirectorySeparator = delim;
EncodedName = encodedName;
Attributes = attributes;
Engine = engine;
}
ImapFolderConstructorArgs ()
{
}
/// <summary>
/// Get the folder attributes.
/// </summary>
/// <remarks>
/// Gets the folder attributes.
/// </remarks>
/// <value>The folder attributes.</value>
public FolderAttributes Attributes {
get; private set;
}
/// <summary>
/// Get the directory separator.
/// </summary>
/// <remarks>
/// Gets the directory separator.
/// </remarks>
/// <value>The directory separator.</value>
public char DirectorySeparator {
get; private set;
}
/// <summary>
/// Get the full name of the folder.
/// </summary>
/// <remarks>
/// This is the equivalent of the full path of a file on a file system.
/// </remarks>
/// <value>The full name of the folder.</value>
public string FullName {
get; private set;
}
/// <summary>
/// Get the name of the folder.
/// </summary>
/// <remarks>
/// This is the equivalent of the file name of a file on the file system.
/// </remarks>
/// <value>The name of the folder.</value>
public string Name {
get; private set;
}
static string GetBaseName (string fullName, char delim)
{
var names = fullName.Split (new [] { delim }, StringSplitOptions.RemoveEmptyEntries);
return names.Length > 0 ? names[names.Length - 1] : fullName;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
//
// ImapImplementation.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.Collections.Generic;
namespace MailKit.Net.Imap {
/// <summary>
/// The details of an IMAP client or server implementation.
/// </summary>
/// <remarks>
/// Allows an IMAP client and server to share their implementation details
/// with each other for the purposes of debugging.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
public class ImapImplementation
{
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapImplementation"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="MailKit.Net.Imap.ImapImplementation"/>.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
public ImapImplementation ()
{
Properties = new Dictionary<string, string> ();
}
string GetProperty (string property)
{
string value;
Properties.TryGetValue (property, out value);
return value;
}
/// <summary>
/// Get the identification properties.
/// </summary>
/// <remarks>
/// Gets the dictionary of raw identification properties.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The properties.</value>
public Dictionary<string, string> Properties {
get; private set;
}
/// <summary>
/// Get or set the name of the program.
/// </summary>
/// <remarks>
/// Gets or sets the name of the program.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The program name.</value>
public string Name {
get { return GetProperty ("name"); }
set { Properties["name"] = value; }
}
/// <summary>
/// Get or set the version of the program.
/// </summary>
/// <remarks>
/// Gets or sets the version of the program.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\ImapExamples.cs" region="Capabilities"/>
/// </example>
/// <value>The program version.</value>
public string Version {
get { return GetProperty ("version"); }
set { Properties["version"] = value; }
}
/// <summary>
/// Get or set the name of the operating system.
/// </summary>
/// <remarks>
/// Gets or sets the name of the operating system.
/// </remarks>
/// <value>The name of the operation system.</value>
public string OS {
get { return GetProperty ("os"); }
set { Properties["os"] = value; }
}
/// <summary>
/// Get or set the version of the operating system.
/// </summary>
/// <remarks>
/// Gets or sets the version of the operating system.
/// </remarks>
/// <value>The version of the operation system.</value>
public string OSVersion {
get { return GetProperty ("os-version"); }
set { Properties["os-version"] = value; }
}
/// <summary>
/// Get or set the name of the vendor.
/// </summary>
/// <remarks>
/// Gets or sets the name of the vendor.
/// </remarks>
/// <value>The name of the vendor.</value>
public string Vendor {
get { return GetProperty ("vendor"); }
set { Properties["vendor"] = value; }
}
/// <summary>
/// Get or set the support URL.
/// </summary>
/// <remarks>
/// Gets or sets the support URL.
/// </remarks>
/// <value>The support URL.</value>
public string SupportUrl {
get { return GetProperty ("support-url"); }
set { Properties["support-url"] = value; }
}
/// <summary>
/// Get or set the postal address of the vendor.
/// </summary>
/// <remarks>
/// Gets or sets the postal address of the vendor.
/// </remarks>
/// <value>The postal address.</value>
public string Address {
get { return GetProperty ("address"); }
set { Properties["address"] = value; }
}
/// <summary>
/// Get or set the release date of the program.
/// </summary>
/// <remarks>
/// Gets or sets the release date of the program.
/// </remarks>
/// <value>The release date.</value>
public string ReleaseDate {
get { return GetProperty ("date"); }
set { Properties["date"] = value; }
}
/// <summary>
/// Get or set the command used to start the program.
/// </summary>
/// <remarks>
/// Gets or sets the command used to start the program.
/// </remarks>
/// <value>The command used to start the program.</value>
public string Command {
get { return GetProperty ("command"); }
set { Properties["command"] = value; }
}
/// <summary>
/// Get or set the command-line arguments used to start the program.
/// </summary>
/// <remarks>
/// Gets or sets the command-line arguments used to start the program.
/// </remarks>
/// <value>The command-line arguments used to start the program.</value>
public string Arguments {
get { return GetProperty ("arguments"); }
set { Properties["arguments"] = value; }
}
/// <summary>
/// Get or set the environment variables available to the program.
/// </summary>
/// <remarks>
/// Get or set the environment variables available to the program.
/// </remarks>
/// <value>The environment variables.</value>
public string Environment {
get { return GetProperty ("environment"); }
set { Properties["environment"] = value; }
}
}
}

View File

@ -0,0 +1,109 @@
//
// ImapException.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;
#if SERIALIZABLE
using System.Security;
using System.Runtime.Serialization;
#endif
namespace MailKit.Net.Imap {
/// <summary>
/// An IMAP protocol exception.
/// </summary>
/// <remarks>
/// The exception that is thrown when there is an error communicating with an IMAP server. An
/// <see cref="ImapProtocolException"/> is typically fatal and requires the <see cref="ImapClient"/>
/// to be reconnected.
/// </remarks>
#if SERIALIZABLE
[Serializable]
#endif
public class ImapProtocolException : ProtocolException
{
#if SERIALIZABLE
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapProtocolException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapProtocolException"/> from the serialized data.
/// </remarks>
/// <param name="info">The serialization info.</param>
/// <param name="context">The streaming context.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="info"/> is <c>null</c>.
/// </exception>
[SecuritySafeCritical]
protected ImapProtocolException (SerializationInfo info, StreamingContext context) : base (info, context)
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapProtocolException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapProtocolException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
/// <param name="innerException">An inner exception.</param>
public ImapProtocolException (string message, Exception innerException) : base (message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapProtocolException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapProtocolException"/>.
/// </remarks>
/// <param name="message">The error message.</param>
public ImapProtocolException (string message) : base (message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MailKit.Net.Imap.ImapProtocolException"/> class.
/// </summary>
/// <remarks>
/// Creates a new <see cref="ImapProtocolException"/>.
/// </remarks>
public ImapProtocolException ()
{
}
/// <summary>
/// Gets or sets whether or not this exception was thrown due to an unexpected token.
/// </summary>
/// <remarks>
/// Gets or sets whether or not this exception was thrown due to an unexpected token.
/// </remarks>
/// <value><c>true</c> if an unexpected token was encountered; otherwise, <c>false</c>.</value>
internal bool UnexpectedToken {
get; set;
}
}
}

View File

@ -0,0 +1,373 @@
//
// ImapResponseCode.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.
//
namespace MailKit.Net.Imap {
enum ImapResponseCodeType : byte {
Alert,
BadCharset,
Capability,
NewName,
Parse,
PermanentFlags,
ReadOnly,
ReadWrite,
TryCreate,
UidNext,
UidValidity,
Unseen,
// RESP-CODES introduced in rfc2221:
Referral,
// RESP-CODES introduced in rfc3516,
UnknownCte,
// RESP-CODES introduced in rfc4315:
AppendUid,
CopyUid,
UidNotSticky,
// RESP-CODES introduced in rfc4467:
UrlMech,
// RESP-CODES introduced in rfc4469:
BadUrl,
TooBig,
// RESP-CODES introduced in rfc4551:
HighestModSeq,
Modified,
NoModSeq,
// RESP-CODES introduced in rfc4978:
CompressionActive,
// RESP-CODES introduced in rfc5162:
Closed,
// RESP-CODES introduced in rfc5182:
NotSaved,
// RESP-CODES introduced in rfc5255:
BadComparator,
// RESP-CODES introduced in rfc5257:
Annotate,
Annotations,
// RESP-CODES introduced in rfc5259:
MaxConvertMessages,
MaxConvertParts,
TempFail,
// RESP-CODES introduced in rfc5267:
NoUpdate,
// RESP-CODES introduced in rfc5464:
Metadata,
// RESP-CODES introduced in rfc5465:
NotificationOverflow,
BadEvent,
// RESP-CODES introduced in rfc5466:
UndefinedFilter,
// RESP-CODES introduced in rfc5530:
Unavailable,
AuthenticationFailed,
AuthorizationFailed,
Expired,
PrivacyRequired,
ContactAdmin,
NoPerm,
InUse,
ExpungeIssued,
Corruption,
ServerBug,
ClientBug,
CanNot,
Limit,
OverQuota,
AlreadyExists,
NonExistent,
// RESP-CODES introduced in rfc6154:
UseAttr,
// RESP-CODES introduced in rfc8474:
MailboxId,
Unknown = 255
}
class ImapResponseCode
{
public readonly ImapResponseCodeType Type;
public bool IsTagged, IsError;
public string Message;
internal ImapResponseCode (ImapResponseCodeType type, bool isError)
{
IsError = isError;
Type = type;
}
public static ImapResponseCode Create (ImapResponseCodeType type)
{
switch (type) {
case ImapResponseCodeType.Alert: return new ImapResponseCode (type, false);
case ImapResponseCodeType.BadCharset: return new ImapResponseCode (type, true);
case ImapResponseCodeType.Capability: return new ImapResponseCode (type, false);
case ImapResponseCodeType.NewName: return new NewNameResponseCode (type);
case ImapResponseCodeType.Parse: return new ImapResponseCode (type, true);
case ImapResponseCodeType.PermanentFlags: return new PermanentFlagsResponseCode (type);
case ImapResponseCodeType.ReadOnly: return new ImapResponseCode (type, false);
case ImapResponseCodeType.ReadWrite: return new ImapResponseCode (type, false);
case ImapResponseCodeType.TryCreate: return new ImapResponseCode (type, true);
case ImapResponseCodeType.UidNext: return new UidNextResponseCode (type);
case ImapResponseCodeType.UidValidity: return new UidValidityResponseCode (type);
case ImapResponseCodeType.Unseen: return new UnseenResponseCode (type);
case ImapResponseCodeType.Referral: return new ImapResponseCode (type, false);
case ImapResponseCodeType.UnknownCte: return new ImapResponseCode (type, true);
case ImapResponseCodeType.AppendUid: return new AppendUidResponseCode (type);
case ImapResponseCodeType.CopyUid: return new CopyUidResponseCode (type);
case ImapResponseCodeType.UidNotSticky: return new ImapResponseCode (type, false);
case ImapResponseCodeType.UrlMech: return new ImapResponseCode (type, false);
case ImapResponseCodeType.BadUrl: return new BadUrlResponseCode (type);
case ImapResponseCodeType.TooBig: return new ImapResponseCode (type, true);
case ImapResponseCodeType.HighestModSeq: return new HighestModSeqResponseCode (type);
case ImapResponseCodeType.Modified: return new ModifiedResponseCode (type);
case ImapResponseCodeType.NoModSeq: return new ImapResponseCode (type, false);
case ImapResponseCodeType.CompressionActive: return new ImapResponseCode (type, true);
case ImapResponseCodeType.Closed: return new ImapResponseCode (type, false);
case ImapResponseCodeType.NotSaved: return new ImapResponseCode (type, true);
case ImapResponseCodeType.BadComparator: return new ImapResponseCode (type, true);
case ImapResponseCodeType.Annotate: return new AnnotateResponseCode (type);
case ImapResponseCodeType.Annotations: return new AnnotationsResponseCode (type);
case ImapResponseCodeType.MaxConvertMessages: return new MaxConvertResponseCode (type);
case ImapResponseCodeType.MaxConvertParts: return new MaxConvertResponseCode (type);
case ImapResponseCodeType.TempFail: return new ImapResponseCode (type, true);
case ImapResponseCodeType.NoUpdate: return new NoUpdateResponseCode (type);
case ImapResponseCodeType.Metadata: return new MetadataResponseCode (type);
case ImapResponseCodeType.NotificationOverflow: return new ImapResponseCode (type, false);
case ImapResponseCodeType.BadEvent: return new ImapResponseCode (type, true);
case ImapResponseCodeType.UndefinedFilter: return new UndefinedFilterResponseCode (type);
case ImapResponseCodeType.Unavailable: return new ImapResponseCode (type, true);
case ImapResponseCodeType.AuthenticationFailed: return new ImapResponseCode (type, true);
case ImapResponseCodeType.AuthorizationFailed: return new ImapResponseCode (type, true);
case ImapResponseCodeType.Expired: return new ImapResponseCode (type, true);
case ImapResponseCodeType.PrivacyRequired: return new ImapResponseCode (type, true);
case ImapResponseCodeType.ContactAdmin: return new ImapResponseCode (type, true);
case ImapResponseCodeType.NoPerm: return new ImapResponseCode (type, true);
case ImapResponseCodeType.InUse: return new ImapResponseCode (type, true);
case ImapResponseCodeType.ExpungeIssued: return new ImapResponseCode (type, true);
case ImapResponseCodeType.Corruption: return new ImapResponseCode (type, true);
case ImapResponseCodeType.ServerBug: return new ImapResponseCode (type, true);
case ImapResponseCodeType.ClientBug: return new ImapResponseCode (type, true);
case ImapResponseCodeType.CanNot: return new ImapResponseCode (type, true);
case ImapResponseCodeType.Limit: return new ImapResponseCode (type, true);
case ImapResponseCodeType.OverQuota: return new ImapResponseCode (type, true);
case ImapResponseCodeType.AlreadyExists: return new ImapResponseCode (type, true);
case ImapResponseCodeType.NonExistent: return new ImapResponseCode (type, true);
case ImapResponseCodeType.UseAttr: return new ImapResponseCode (type, true);
case ImapResponseCodeType.MailboxId: return new MailboxIdResponseCode (type);
default: return new ImapResponseCode (type, true);
}
}
}
class NewNameResponseCode : ImapResponseCode
{
public string OldName;
public string NewName;
internal NewNameResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class PermanentFlagsResponseCode : ImapResponseCode
{
public MessageFlags Flags;
internal PermanentFlagsResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class UidNextResponseCode : ImapResponseCode
{
public UniqueId Uid;
internal UidNextResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class UidValidityResponseCode : ImapResponseCode
{
public uint UidValidity;
internal UidValidityResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class UnseenResponseCode : ImapResponseCode
{
public int Index;
internal UnseenResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class AppendUidResponseCode : UidValidityResponseCode
{
public UniqueIdSet UidSet;
internal AppendUidResponseCode (ImapResponseCodeType type) : base (type)
{
}
}
class CopyUidResponseCode : UidValidityResponseCode
{
public UniqueIdSet SrcUidSet, DestUidSet;
internal CopyUidResponseCode (ImapResponseCodeType type) : base (type)
{
}
}
class BadUrlResponseCode : ImapResponseCode
{
public string BadUrl;
internal BadUrlResponseCode (ImapResponseCodeType type) : base (type, true)
{
}
}
class HighestModSeqResponseCode : ImapResponseCode
{
public ulong HighestModSeq;
internal HighestModSeqResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class ModifiedResponseCode : ImapResponseCode
{
public UniqueIdSet UidSet;
internal ModifiedResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
class MaxConvertResponseCode : ImapResponseCode
{
public uint MaxConvert;
internal MaxConvertResponseCode (ImapResponseCodeType type) : base (type, true)
{
}
}
class NoUpdateResponseCode : ImapResponseCode
{
public string Tag;
internal NoUpdateResponseCode (ImapResponseCodeType type) : base (type, true)
{
}
}
enum AnnotateResponseCodeSubType
{
TooBig,
TooMany
}
class AnnotateResponseCode : ImapResponseCode
{
public AnnotateResponseCodeSubType SubType;
internal AnnotateResponseCode (ImapResponseCodeType type) : base (type, true)
{
}
}
class AnnotationsResponseCode : ImapResponseCode
{
public AnnotationAccess Access;
public AnnotationScope Scopes;
public uint MaxSize;
internal AnnotationsResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
enum MetadataResponseCodeSubType
{
LongEntries,
MaxSize,
TooMany,
NoPrivate
}
class MetadataResponseCode : ImapResponseCode
{
public MetadataResponseCodeSubType SubType;
public uint Value;
internal MetadataResponseCode (ImapResponseCodeType type) : base (type, true)
{
}
}
class UndefinedFilterResponseCode : ImapResponseCode
{
public string Name;
internal UndefinedFilterResponseCode (ImapResponseCodeType type) : base (type, true)
{
}
}
class MailboxIdResponseCode : ImapResponseCode
{
public string MailboxId;
internal MailboxIdResponseCode (ImapResponseCodeType type) : base (type, false)
{
}
}
}

View File

@ -0,0 +1,83 @@
//
// ImapSearchQueryOptimizer.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 MailKit.Search;
namespace MailKit.Net.Imap {
class ImapSearchQueryOptimizer : ISearchQueryOptimizer
{
#region ISearchQueryOptimizer implementation
public SearchQuery Reduce (SearchQuery expr)
{
if (expr.Term == SearchTerm.And) {
var and = (BinarySearchQuery) expr;
if (and.Left.Term == SearchTerm.All)
return and.Right.Optimize (this);
if (and.Right.Term == SearchTerm.All)
return and.Left.Optimize (this);
} else if (expr.Term == SearchTerm.Or) {
var or = (BinarySearchQuery) expr;
if (or.Left.Term == SearchTerm.All)
return SearchQuery.All;
if (or.Right.Term == SearchTerm.All)
return SearchQuery.All;
} else if (expr.Term == SearchTerm.Not) {
var unary = (UnarySearchQuery) expr;
switch (unary.Operand.Term) {
case SearchTerm.Not: return ((UnarySearchQuery) unary.Operand).Operand.Optimize (this);
case SearchTerm.NotAnswered: return SearchQuery.Answered;
case SearchTerm.Answered: return SearchQuery.NotAnswered;
case SearchTerm.NotDeleted: return SearchQuery.Deleted;
case SearchTerm.Deleted: return SearchQuery.NotDeleted;
case SearchTerm.NotDraft: return SearchQuery.Draft;
case SearchTerm.Draft: return SearchQuery.NotDraft;
case SearchTerm.NotFlagged: return SearchQuery.Flagged;
case SearchTerm.Flagged: return SearchQuery.NotFlagged;
case SearchTerm.NotRecent: return SearchQuery.Recent;
case SearchTerm.Recent: return SearchQuery.NotRecent;
case SearchTerm.NotSeen: return SearchQuery.Seen;
case SearchTerm.Seen: return SearchQuery.NotSeen;
}
if (unary.Operand.Term == SearchTerm.Keyword)
return new TextSearchQuery (SearchTerm.NotKeyword, ((TextSearchQuery) unary.Operand).Text);
if (unary.Operand.Term == SearchTerm.NotKeyword)
return new TextSearchQuery (SearchTerm.Keyword, ((TextSearchQuery) unary.Operand).Text);
}
return expr;
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
//
// ImapToken.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.Globalization;
namespace MailKit.Net.Imap {
enum ImapTokenType {
NoData = -7,
Error = -6,
Nil = -5,
Atom = -4,
Flag = -3,
QString = -2,
Literal = -1,
// character tokens:
Eoln = (int) '\n',
OpenParen = (int) '(',
CloseParen = (int) ')',
Asterisk = (int) '*',
OpenBracket = (int) '[',
CloseBracket = (int) ']',
}
class ImapToken
{
public readonly ImapTokenType Type;
public readonly object Value;
public ImapToken (ImapTokenType type, object value = null)
{
Value = value;
Type = type;
//System.Console.WriteLine ("token: {0}", this);
}
public override string ToString ()
{
switch (Type) {
case ImapTokenType.NoData: return "<no data>";
case ImapTokenType.Nil: return "NIL";
case ImapTokenType.Atom: return "[atom: " + (string) Value + "]";
case ImapTokenType.Flag: return "[flag: " + (string) Value + "]";
case ImapTokenType.QString: return "[qstring: \"" + (string) Value + "\"]";
case ImapTokenType.Literal: return "{" + (int) Value + "}";
case ImapTokenType.Eoln: return "'\\n'";
case ImapTokenType.OpenParen: return "'('";
case ImapTokenType.CloseParen: return "')'";
case ImapTokenType.Asterisk: return "'*'";
case ImapTokenType.OpenBracket: return "'['";
case ImapTokenType.CloseBracket: return "']'";
default: return string.Format (CultureInfo.InvariantCulture, "[{0}: '{1}']", Type, Value);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,298 @@
//
// NetworkStream.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.Threading;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace MailKit.Net
{
class NetworkStream : Stream
{
SocketAsyncEventArgs send;
SocketAsyncEventArgs recv;
bool ownsSocket;
bool connected;
public NetworkStream (Socket socket, bool ownsSocket)
{
send = new SocketAsyncEventArgs ();
send.Completed += AsyncOperationCompleted;
send.AcceptSocket = socket;
recv = new SocketAsyncEventArgs ();
recv.Completed += AsyncOperationCompleted;
recv.AcceptSocket = socket;
this.ownsSocket = ownsSocket;
connected = socket.Connected;
Socket = socket;
}
~NetworkStream ()
{
Dispose (false);
}
public Socket Socket {
get; private set;
}
public bool DataAvailable {
get { return connected && Socket.Available > 0; }
}
public override bool CanRead {
get { return connected; }
}
public override bool CanWrite {
get { return connected; }
}
public override bool CanSeek {
get { return false; }
}
public override bool CanTimeout {
get { return connected; }
}
public override long Length {
get { throw new NotSupportedException (); }
}
public override long Position {
get { throw new NotSupportedException (); }
set { throw new NotSupportedException (); }
}
public override int ReadTimeout {
get {
int timeout = Socket.ReceiveTimeout;
return timeout == 0 ? Timeout.Infinite : timeout;
}
set {
if (value <= 0 && value != Timeout.Infinite)
throw new ArgumentOutOfRangeException (nameof (value));
Socket.ReceiveTimeout = value;
}
}
public override int WriteTimeout {
get {
int timeout = Socket.SendTimeout;
return timeout == 0 ? Timeout.Infinite : timeout;
}
set {
if (value <= 0 && value != Timeout.Infinite)
throw new ArgumentOutOfRangeException (nameof (value));
Socket.SendTimeout = value;
}
}
void AsyncOperationCompleted (object sender, SocketAsyncEventArgs args)
{
var tcs = (TaskCompletionSource<bool>) args.UserToken;
if (args.SocketError == SocketError.Success) {
tcs.TrySetResult (true);
return;
}
tcs.TrySetException (new SocketException ((int) args.SocketError));
}
void Disconnect ()
{
try {
Socket.Dispose ();
} catch {
return;
} finally {
connected = false;
send.Dispose ();
send = null;
recv.Dispose ();
recv = null;
}
}
public override int Read (byte[] buffer, int offset, int count)
{
try {
return Socket.Receive (buffer, offset, count, SocketFlags.None);
} catch (SocketException ex) {
throw new IOException (ex.Message, ex);
}
}
public override async Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested ();
var tcs = new TaskCompletionSource<bool> ();
using (var timeout = new CancellationTokenSource (ReadTimeout)) {
using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken, timeout.Token)) {
using (var registration = linked.Token.Register (() => tcs.TrySetCanceled (), false)) {
recv.SetBuffer (buffer, offset, count);
recv.UserToken = tcs;
if (!Socket.ReceiveAsync (recv))
AsyncOperationCompleted (null, recv);
try {
await tcs.Task.ConfigureAwait (false);
return recv.BytesTransferred;
} catch (OperationCanceledException) {
if (Socket.Connected)
Socket.Shutdown (SocketShutdown.Both);
Disconnect ();
throw;
} catch (Exception ex) {
Disconnect ();
if (ex is SocketException)
throw new IOException (ex.Message, ex);
throw;
}
}
}
}
}
public override void Write (byte[] buffer, int offset, int count)
{
try {
Socket.Send (buffer, offset, count, SocketFlags.None);
} catch (SocketException ex) {
throw new IOException (ex.Message, ex);
}
}
public override async Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested ();
var tcs = new TaskCompletionSource<bool> ();
using (var timeout = new CancellationTokenSource (WriteTimeout)) {
using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken, timeout.Token)) {
using (var registration = linked.Token.Register (() => tcs.TrySetCanceled (), false)) {
send.SetBuffer (buffer, offset, count);
send.UserToken = tcs;
if (!Socket.SendAsync (send))
AsyncOperationCompleted (null, send);
try {
await tcs.Task.ConfigureAwait (false);
} catch (OperationCanceledException) {
if (Socket.Connected)
Socket.Shutdown (SocketShutdown.Both);
Disconnect ();
throw;
} catch (Exception ex) {
Disconnect ();
if (ex is SocketException)
throw new IOException (ex.Message, ex);
throw;
}
}
}
}
}
public override void Flush ()
{
}
public override Task FlushAsync (CancellationToken cancellationToken)
{
return Task.FromResult (true);
}
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ();
}
public override void SetLength (long value)
{
throw new NotSupportedException ();
}
public static NetworkStream Get (Stream stream)
{
if (stream is CompressedStream compressed)
stream = compressed.InnerStream;
if (stream is SslStream ssl)
stream = ssl.InnerStream;
return stream as NetworkStream;
}
public void Poll (SelectMode mode, CancellationToken cancellationToken)
{
if (!cancellationToken.CanBeCanceled)
return;
do {
cancellationToken.ThrowIfCancellationRequested ();
// wait 1/4 second and then re-check for cancellation
} while (!Socket.Poll (250000, mode));
cancellationToken.ThrowIfCancellationRequested ();
}
protected override void Dispose (bool disposing)
{
if (disposing) {
if (ownsSocket && connected) {
ownsSocket = false;
Disconnect ();
} else {
send?.Dispose ();
send = null;
recv?.Dispose ();
recv = null;
}
}
base.Dispose (disposing);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,309 @@
//
// IPop3Client.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.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace MailKit.Net.Pop3 {
/// <summary>
/// An interface for a POP3 client.
/// </summary>
/// <remarks>
/// Implemented by <see cref="MailKit.Net.Pop3.Pop3Client"/>.
/// </remarks>
public interface IPop3Client : IMailSpool
{
/// <summary>
/// Gets the capabilities supported by the POP3 server.
/// </summary>
/// <remarks>
/// The capabilities will not be known until a successful connection has been made
/// and may change once the client is authenticated.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\Pop3Examples.cs" region="Capabilities"/>
/// </example>
/// <value>The capabilities.</value>
/// <exception cref="System.ArgumentException">
/// Capabilities cannot be enabled, they may only be disabled.
/// </exception>
Pop3Capabilities Capabilities { get; set; }
/// <summary>
/// Gets the expiration policy.
/// </summary>
/// <remarks>
/// <para>If the server supports the EXPIRE capability (<see cref="Pop3Capabilities.Expire"/>), the value
/// of the <see cref="ExpirePolicy"/> property will reflect the value advertized by the server.</para>
/// <para>A value of <c>-1</c> indicates that messages will never expire.</para>
/// <para>A value of <c>0</c> indicates that messages that have been retrieved during the current session
/// will be purged immediately after the connection is closed via the <c>QUIT</c> command.</para>
/// <para>Values larger than <c>0</c> indicate the minimum number of days that the server will retain
/// messages which have been retrieved.</para>
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\Pop3Examples.cs" region="Capabilities"/>
/// </example>
/// <value>The expiration policy.</value>
int ExpirePolicy { get; }
/// <summary>
/// Gets the implementation details of the server.
/// </summary>
/// <remarks>
/// If the server advertizes its implementation details, this value will be set to a string containing the
/// information details provided by the server.
/// </remarks>
/// <value>The implementation details.</value>
string Implementation { get; }
/// <summary>
/// Gets the minimum delay, in milliseconds, between logins.
/// </summary>
/// <remarks>
/// If the server supports the LOGIN-DELAY capability (<see cref="Pop3Capabilities.LoginDelay"/>), this value
/// will be set to the minimum number of milliseconds that the client must wait between logins.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\Pop3Examples.cs" region="Capabilities"/>
/// </example>
/// <value>The login delay.</value>
int LoginDelay { get; }
/// <summary>
/// Enable UTF8 mode.
/// </summary>
/// <remarks>
/// The POP3 UTF8 extension allows the client to retrieve messages in the UTF-8 encoding and
/// may also allow the user to authenticate using a UTF-8 encoded username or password.
/// </remarks>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="Pop3Client"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="Pop3Client"/> is not connected.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// The <see cref="Pop3Client"/> has already been authenticated.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The POP3 server does not support the UTF8 extension.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="Pop3CommandException">
/// The POP3 command failed.
/// </exception>
/// <exception cref="Pop3ProtocolException">
/// A POP3 protocol error occurred.
/// </exception>
void EnableUTF8 (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously enable UTF8 mode.
/// </summary>
/// <remarks>
/// The POP3 UTF8 extension allows the client to retrieve messages in the UTF-8 encoding and
/// may also allow the user to authenticate using a UTF-8 encoded username or password.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="Pop3Client"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="Pop3Client"/> is not connected.
/// </exception>
/// <exception cref="System.InvalidOperationException">
/// The <see cref="Pop3Client"/> has already been authenticated.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The POP3 server does not support the UTF8 extension.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="Pop3CommandException">
/// The POP3 command failed.
/// </exception>
/// <exception cref="Pop3ProtocolException">
/// A POP3 protocol error occurred.
/// </exception>
Task EnableUTF8Async (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Get the list of languages supported by the POP3 server.
/// </summary>
/// <remarks>
/// If the POP3 server supports the LANG extension, it is possible to
/// query the list of languages supported by the POP3 server that can
/// be used for error messages.
/// </remarks>
/// <returns>The supported languages.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="Pop3Client"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="Pop3Client"/> is not connected.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The POP3 server does not support the LANG extension.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="Pop3CommandException">
/// The POP3 command failed.
/// </exception>
/// <exception cref="Pop3ProtocolException">
/// A POP3 protocol error occurred.
/// </exception>
IList<Pop3Language> GetLanguages (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously get the list of languages supported by the POP3 server.
/// </summary>
/// <remarks>
/// If the POP3 server supports the LANG extension, it is possible to
/// query the list of languages supported by the POP3 server that can
/// be used for error messages.
/// </remarks>
/// <returns>The supported languages.</returns>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="Pop3Client"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="Pop3Client"/> is not connected.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The POP3 server does not support the LANG extension.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="Pop3CommandException">
/// The POP3 command failed.
/// </exception>
/// <exception cref="Pop3ProtocolException">
/// A POP3 protocol error occurred.
/// </exception>
Task<IList<Pop3Language>> GetLanguagesAsync (CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Set the language used by the POP3 server for error messages.
/// </summary>
/// <remarks>
/// If the POP3 server supports the LANG extension, it is possible to
/// set the language used by the POP3 server for error messages.
/// </remarks>
/// <param name="lang">The language code.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="lang"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="lang"/> is empty.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="Pop3Client"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="Pop3Client"/> is not connected.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The POP3 server does not support the LANG extension.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="Pop3CommandException">
/// The POP3 command failed.
/// </exception>
/// <exception cref="Pop3ProtocolException">
/// A POP3 protocol error occurred.
/// </exception>
void SetLanguage (string lang, CancellationToken cancellationToken = default (CancellationToken));
/// <summary>
/// Asynchronously set the language used by the POP3 server for error messages.
/// </summary>
/// <remarks>
/// If the POP3 server supports the LANG extension, it is possible to
/// set the language used by the POP3 server for error messages.
/// </remarks>
/// <returns>An asynchronous task context.</returns>
/// <param name="lang">The language code.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="lang"/> is <c>null</c>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="lang"/> is empty.
/// </exception>
/// <exception cref="System.ObjectDisposedException">
/// The <see cref="Pop3Client"/> has been disposed.
/// </exception>
/// <exception cref="ServiceNotConnectedException">
/// The <see cref="Pop3Client"/> is not connected.
/// </exception>
/// <exception cref="System.OperationCanceledException">
/// The operation was canceled via the cancellation token.
/// </exception>
/// <exception cref="System.NotSupportedException">
/// The POP3 server does not support the LANG extension.
/// </exception>
/// <exception cref="System.IO.IOException">
/// An I/O error occurred.
/// </exception>
/// <exception cref="Pop3CommandException">
/// The POP3 command failed.
/// </exception>
/// <exception cref="Pop3ProtocolException">
/// A POP3 protocol error occurred.
/// </exception>
Task SetLanguageAsync (string lang, CancellationToken cancellationToken = default (CancellationToken));
}
}

View File

@ -0,0 +1,129 @@
//
// Pop3Capabilities.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;
namespace MailKit.Net.Pop3 {
/// <summary>
/// Capabilities supported by a POP3 server.
/// </summary>
/// <remarks>
/// Capabilities are read as part of the response to the <c>CAPA</c> command that
/// is issued during the connection and authentication phases of the
/// <see cref="Pop3Client"/>.
/// </remarks>
/// <example>
/// <code language="c#" source="Examples\Pop3Examples.cs" region="Capabilities"/>
/// </example>
[Flags]
public enum Pop3Capabilities : uint {
/// <summary>
/// The server does not support any additional extensions.
/// </summary>
None = 0,
/// <summary>
/// The server supports <a href="https://tools.ietf.org/html/rfc1939#page-15">APOP</a>
/// authentication.
/// </summary>
Apop = 1 << 0,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2449">EXPIRE</a> extension
/// and defines the expiration policy for messages (see <see cref="Pop3Client.ExpirePolicy"/>).
/// </summary>
Expire = 1 << 1,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2449">LOGIN-DELAY</a> extension,
/// allowing the server to specify to the client a minimum number of seconds between login attempts
/// (see <see cref="Pop3Client.LoginDelay"/>).
/// </summary>
LoginDelay = 1 << 2,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2449">PIPELINING</a> extension,
/// allowing the client to batch multiple requests to the server at at time.
/// </summary>
Pipelining = 1 << 3,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2449">RESP-CODES</a> extension,
/// allowing the server to provide clients with extended information in error responses.
/// </summary>
ResponseCodes = 1 << 4,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2449">SASL</a> authentication
/// extension, allowing the client to authenticate using the advertized authentication mechanisms
/// (see <see cref="Pop3Client.AuthenticationMechanisms"/>).
/// </summary>
Sasl = 1 << 5,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc2595">STLS</a> extension,
/// allowing clients to switch to an encrypted SSL/TLS connection after connecting.
/// </summary>
StartTLS = 1 << 6,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc1939#page-11">TOP</a> command,
/// allowing clients to fetch the headers plus an arbitrary number of lines.
/// </summary>
Top = 1 << 7,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc1939#page-12">UIDL</a> command,
/// allowing the client to refer to messages via a UID as opposed to a sequence ID.
/// </summary>
UIDL = 1 << 8,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc1939#page-13">USER</a>
/// authentication command, allowing the client to authenticate via a plain-text username
/// and password command (not recommended unless no other authentication mechanisms exist).
/// </summary>
User = 1 << 9,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6856">UTF8</a> extension,
/// allowing clients to retrieve messages in the UTF-8 encoding.
/// </summary>
UTF8 = 1 << 10,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6856">UTF8=USER</a> extension,
/// allowing clients to authenticate using UTF-8 encoded usernames and passwords.
/// </summary>
UTF8User = 1 << 11,
/// <summary>
/// The server supports the <a href="https://tools.ietf.org/html/rfc6856">LANG</a> extension,
/// allowing clients to specify which language the server should use for error strings.
/// </summary>
Lang = 1 << 12,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
//
// Pop3Command.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.Text;
using System.Threading;
using System.Globalization;
using System.Threading.Tasks;
namespace MailKit.Net.Pop3 {
/// <summary>
/// POP3 command handler.
/// </summary>
/// <remarks>
/// All exceptions thrown by the handler are considered fatal and will
/// force-disconnect the connection. If a non-fatal error occurs, set
/// it on the <see cref="Pop3Command.Exception"/> property.
/// </remarks>
delegate Task Pop3CommandHandler (Pop3Engine engine, Pop3Command pc, string text, bool doAsync);
enum Pop3CommandStatus {
Queued = -5,
Active = -4,
Continue = -3,
ProtocolError = -2,
Error = -1,
Ok = 0
}
class Pop3Command
{
public CancellationToken CancellationToken { get; private set; }
public Pop3CommandHandler Handler { get; private set; }
public Encoding Encoding { get; private set; }
public string Command { get; private set; }
public int Id { get; internal set; }
// output
public Pop3CommandStatus Status { get; internal set; }
public ProtocolException Exception { get; set; }
public string StatusText { get; set; }
public Pop3Command (CancellationToken cancellationToken, Pop3CommandHandler handler, Encoding encoding, string format, params object[] args)
{
Command = string.Format (CultureInfo.InvariantCulture, format, args);
CancellationToken = cancellationToken;
Encoding = encoding;
Handler = handler;
}
}
}

Some files were not shown because too many files have changed in this diff Show More