693 lines
31 KiB
C#
693 lines
31 KiB
C#
//
|
|
// 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));
|
|
}
|
|
}
|
|
}
|
|
}
|