// // ImapFolderFlags.cs // // Author: Jeffrey Stedfast // // 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.Text; using System.Threading; using System.Globalization; using System.Threading.Tasks; using System.Collections.Generic; namespace MailKit.Net.Imap { public partial class ImapFolder { void ProcessUnmodified (ImapCommand ic, ref UniqueIdSet uids, ulong? modseq) { if (modseq.HasValue) { foreach (var rc in ic.RespCodes.OfType ()) { if (uids != null) uids.AddRange (rc.UidSet); else uids = rc.UidSet; } } } IList GetUnmodified (ImapCommand ic, ulong? modseq) { if (modseq.HasValue) { var rc = ic.RespCodes.OfType ().FirstOrDefault (); if (rc != null) { var unmodified = new int[rc.UidSet.Count]; for (int i = 0; i < unmodified.Length; i++) unmodified[i] = (int) (rc.UidSet[i].Id - 1); return unmodified; } } return new int[0]; } async Task> ModifyFlagsAsync (IList uids, ulong? modseq, MessageFlags flags, HashSet keywords, string action, 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."); CheckState (true, true); if (uids.Count == 0) return new UniqueId[0]; var flaglist = ImapUtils.FormatFlagsList (flags & PermanentFlags, keywords != null ? keywords.Count : 0); var keywordList = keywords != null ? keywords.ToArray () : new object[0]; UniqueIdSet unmodified = null; var @params = string.Empty; if (modseq.HasValue) @params = string.Format (CultureInfo.InvariantCulture, " (UNCHANGEDSINCE {0})", modseq.Value); var command = string.Format ("UID STORE %s{0} {1} {2}\r\n", @params, action, flaglist); foreach (var ic in Engine.QueueCommands (cancellationToken, this, command, uids, keywordList)) { 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; } /// /// Adds a set of flags to the specified messages. /// /// /// Adds a set of flags to the specified messages. /// /// The UIDs of the messages. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void AddFlags (IList uids, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { bool emptyUserFlags = keywords == null || keywords.Count == 0; if ((flags & SettableFlags) == 0 && emptyUserFlags) throw new ArgumentException ("No flags were specified.", nameof (flags)); ModifyFlagsAsync (uids, null, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously adds a set of flags to the specified messages. /// /// /// Adds a set of flags to the specified messages. /// /// An asynchronous task context. /// The UIDs of the messages. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task AddFlagsAsync (IList uids, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { bool emptyUserFlags = keywords == null || keywords.Count == 0; if ((flags & SettableFlags) == 0 && emptyUserFlags) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (uids, null, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", true, cancellationToken); } /// /// Removes a set of flags from the specified messages. /// /// /// Removes a set of flags from the specified messages. /// /// The UIDs of the messages. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void RemoveFlags (IList uids, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); ModifyFlagsAsync (uids, null, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously removes a set of flags from the specified messages. /// /// /// Removes a set of flags from the specified messages. /// /// An asynchronous task context. /// The UIDs of the messages. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task RemoveFlagsAsync (IList uids, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (uids, null, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", true, cancellationToken); } /// /// Sets the flags of the specified messages. /// /// /// Sets the flags of the specified messages. /// /// The UIDs of the messages. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void SetFlags (IList uids, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { ModifyFlagsAsync (uids, null, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously sets the flags of the specified messages. /// /// /// Sets the flags of the specified messages. /// /// An asynchronous task context. /// The UIDs of the messages. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task SetFlagsAsync (IList uids, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { return ModifyFlagsAsync (uids, null, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", true, cancellationToken); } /// /// Adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList AddFlags (IList uids, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (uids, modseq, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> AddFlagsAsync (IList uids, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (uids, modseq, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", true, cancellationToken); } /// /// Removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList RemoveFlags (IList uids, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (uids, modseq, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> RemoveFlagsAsync (IList uids, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (uids, modseq, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", true, cancellationToken); } /// /// Sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList SetFlags (IList uids, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { return ModifyFlagsAsync (uids, modseq, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> SetFlagsAsync (IList uids, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { return ModifyFlagsAsync (uids, modseq, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", true, cancellationToken); } async Task> ModifyFlagsAsync (IList indexes, ulong? modseq, MessageFlags flags, HashSet keywords, string action, 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."); CheckState (true, true); if (indexes.Count == 0) return new int[0]; var flaglist = ImapUtils.FormatFlagsList (flags & PermanentFlags, keywords != null ? keywords.Count : 0); var keywordList = keywords != null ? keywords.ToArray () : new object [0]; var set = ImapUtils.FormatIndexSet (indexes); var @params = string.Empty; if (modseq.HasValue) @params = string.Format (CultureInfo.InvariantCulture, " (UNCHANGEDSINCE {0})", modseq.Value); var format = string.Format ("STORE {0}{1} {2} {3}\r\n", set, @params, action, flaglist); var ic = Engine.QueueCommand (cancellationToken, this, format, keywordList); await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); ProcessResponseCodes (ic, null); if (ic.Response != ImapCommandResponse.Ok) throw ImapCommandException.Create ("STORE", ic); return GetUnmodified (ic, modseq); } /// /// Adds a set of flags to the specified messages. /// /// /// Adds a set of flags to the specified messages. /// /// The indexes of the messages. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void AddFlags (IList indexes, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); ModifyFlagsAsync (indexes, null, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously adds a set of flags to the specified messages. /// /// /// Adds a set of flags to the specified messages. /// /// An asynchronous task context. /// The indexes of the messages. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task AddFlagsAsync (IList indexes, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (indexes, null, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", true, cancellationToken); } /// /// Removes a set of flags from the specified messages. /// /// /// Removes a set of flags from the specified messages. /// /// The indexes of the messages. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void RemoveFlags (IList indexes, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); ModifyFlagsAsync (indexes, null, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously removes a set of flags from the specified messages. /// /// /// Removes a set of flags from the specified messages. /// /// An asynchronous task context. /// The indexes of the messages. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task RemoveFlagsAsync (IList indexes, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (indexes, null, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", true, cancellationToken); } /// /// Sets the flags of the specified messages. /// /// /// Sets the flags of the specified messages. /// /// The indexes of the messages. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void SetFlags (IList indexes, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { ModifyFlagsAsync (indexes, null, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously sets the flags of the specified messages. /// /// /// Sets the flags of the specified messages. /// /// An asynchronous task context. /// The indexes of the messages. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task SetFlagsAsync (IList indexes, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { return ModifyFlagsAsync (indexes, null, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", true, cancellationToken); } /// /// Adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList AddFlags (IList indexes, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (indexes, modseq, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of flags to the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The message flags to add. /// A set of user-defined flags to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> AddFlagsAsync (IList indexes, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (indexes, modseq, flags, keywords, silent ? "+FLAGS.SILENT" : "+FLAGS", true, cancellationToken); } /// /// Removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList RemoveFlags (IList indexes, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (indexes, modseq, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of flags from the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The message flags to remove. /// A set of user-defined flags to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// -or- /// No flags were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> RemoveFlagsAsync (IList indexes, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if ((flags & SettableFlags) == 0 && (keywords == null || keywords.Count == 0)) throw new ArgumentException ("No flags were specified.", nameof (flags)); return ModifyFlagsAsync (indexes, modseq, flags, keywords, silent ? "-FLAGS.SILENT" : "-FLAGS", true, cancellationToken); } /// /// Sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList SetFlags (IList indexes, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { return ModifyFlagsAsync (indexes, modseq, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the flags of the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The message flags to set. /// A set of user-defined flags to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The does not support mod-sequences. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> SetFlagsAsync (IList indexes, ulong modseq, MessageFlags flags, HashSet keywords, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { return ModifyFlagsAsync (indexes, modseq, flags, keywords, silent ? "FLAGS.SILENT" : "FLAGS", true, cancellationToken); } string LabelListToString (IList labels, ICollection args) { var list = new StringBuilder ("("); for (int i = 0; i < labels.Count; i++) { if (i > 0) list.Append (' '); if (labels[i] == null) { list.Append ("NIL"); continue; } switch (labels[i]) { case "\\AllMail": case "\\Drafts": case "\\Important": case "\\Inbox": case "\\Spam": case "\\Sent": case "\\Starred": case "\\Trash": list.Append (labels[i]); break; default: list.Append ("%S"); args.Add (Engine.EncodeMailboxName (labels[i])); break; } } list.Append (')'); return list.ToString (); } async Task> ModifyLabelsAsync (IList uids, ulong? modseq, IList labels, string action, bool doAsync, CancellationToken cancellationToken) { if (uids == null) throw new ArgumentNullException (nameof (uids)); if ((Engine.Capabilities & ImapCapabilities.GMailExt1) == 0) throw new NotSupportedException ("The IMAP server does not support the Google Mail extensions."); CheckState (true, true); if (uids.Count == 0) return new UniqueId[0]; var @params = string.Empty; if (modseq.HasValue) @params = string.Format (CultureInfo.InvariantCulture, " (UNCHANGEDSINCE {0})", modseq.Value); var args = new List (); var list = LabelListToString (labels, args); var command = string.Format ("UID STORE %s{0} {1} {2}\r\n", @params, action, list); UniqueIdSet unmodified = null; foreach (var ic in Engine.QueueCommands (cancellationToken, this, command, uids, args.ToArray ())) { 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; } /// /// Add a set of labels to the specified messages. /// /// /// Adds a set of labels to the specified messages. /// /// The UIDs of the messages. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void AddLabels (IList uids, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); ModifyLabelsAsync (uids, null, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously add a set of labels to the specified messages. /// /// /// Adds a set of labels to the specified messages. /// /// An asynchronous task context. /// The UIDs of the messages. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task AddLabelsAsync (IList uids, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (uids, null, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", true, cancellationToken); } /// /// Remove a set of labels from the specified messages. /// /// /// Removes a set of labels from the specified messages. /// /// The UIDs of the messages. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void RemoveLabels (IList uids, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); ModifyLabelsAsync (uids, null, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously remove a set of labels from the specified messages. /// /// /// Removes a set of labels from the specified messages. /// /// An asynchronous task context. /// The UIDs of the messages. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task RemoveLabelsAsync (IList uids, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (uids, null, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", true, cancellationToken); } /// /// Set the labels of the specified messages. /// /// /// Sets the labels of the specified messages. /// /// The UIDs of the messages. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void SetLabels (IList uids, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); ModifyLabelsAsync (uids, null, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously set the labels of the specified messages. /// /// /// Sets the labels of the specified messages. /// /// An asynchronous task context. /// The UIDs of the messages. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task SetLabelsAsync (IList uids, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); return ModifyLabelsAsync (uids, null, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", true, cancellationToken); } /// /// Add a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList AddLabels (IList uids, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (uids, modseq, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously add a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> AddLabelsAsync (IList uids, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (uids, modseq, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", true, cancellationToken); } /// /// Remove a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList RemoveLabels (IList uids, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (uids, modseq, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously remove a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> RemoveLabelsAsync (IList uids, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (uids, modseq, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", true, cancellationToken); } /// /// Set the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList SetLabels (IList uids, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); return ModifyLabelsAsync (uids, modseq, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously set the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// The unique IDs of the messages that were not updated. /// The UIDs of the messages. /// The mod-sequence value. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> SetLabelsAsync (IList uids, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); return ModifyLabelsAsync (uids, modseq, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", true, cancellationToken); } async Task> ModifyLabelsAsync (IList indexes, ulong? modseq, IList labels, string action, bool doAsync, CancellationToken cancellationToken) { if (indexes == null) throw new ArgumentNullException (nameof (indexes)); if ((Engine.Capabilities & ImapCapabilities.GMailExt1) == 0) throw new NotSupportedException ("The IMAP server does not support the Google Mail extensions."); CheckState (true, true); if (indexes.Count == 0) return new int[0]; var set = ImapUtils.FormatIndexSet (indexes); var @params = string.Empty; if (modseq.HasValue) @params = string.Format (CultureInfo.InvariantCulture, " (UNCHANGEDSINCE {0})", modseq.Value); var args = new List (); var list = LabelListToString (labels, args); var format = string.Format ("STORE {0}{1} {2} {3}\r\n", set, @params, action, list); var ic = Engine.QueueCommand (cancellationToken, this, format, args.ToArray ()); await Engine.RunAsync (ic, doAsync).ConfigureAwait (false); ProcessResponseCodes (ic, null); if (ic.Response != ImapCommandResponse.Ok) throw ImapCommandException.Create ("STORE", ic); return GetUnmodified (ic, modseq); } /// /// Add a set of labels to the specified messages. /// /// /// Adds a set of labels to the specified messages. /// /// The indexes of the messages. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void AddLabels (IList indexes, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); ModifyLabelsAsync (indexes, null, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously add a set of labels to the specified messages. /// /// /// Adds a set of labels to the specified messages. /// /// An asynchronous task context. /// The indexes of the messages. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task AddLabelsAsync (IList indexes, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (indexes, null, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", true, cancellationToken); } /// /// Remove a set of labels from the specified messages. /// /// /// Removes a set of labels from the specified messages. /// /// The indexes of the messages. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void RemoveLabels (IList indexes, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); ModifyLabelsAsync (indexes, null, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously remove a set of labels from the specified messages. /// /// /// Removes a set of labels from the specified messages. /// /// An asynchronous task context. /// The indexes of the messages. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task RemoveLabelsAsync (IList indexes, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (indexes, null, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", true, cancellationToken); } /// /// Sets the labels of the specified messages. /// /// /// Sets the labels of the specified messages. /// /// The indexes of the messages. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override void SetLabels (IList indexes, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); ModifyLabelsAsync (indexes, null, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously sets the labels of the specified messages. /// /// /// Sets the labels of the specified messages. /// /// An asynchronous task context. /// The indexes of the messages. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task SetLabelsAsync (IList indexes, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); return ModifyLabelsAsync (indexes, null, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", true, cancellationToken); } /// /// Add a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList AddLabels (IList indexes, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (indexes, modseq, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously add a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Adds a set of labels to the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The labels to add. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> AddLabelsAsync (IList indexes, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (indexes, modseq, labels, silent ? "+X-GM-LABELS.SILENT" : "+X-GM-LABELS", true, cancellationToken); } /// /// Remove a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList RemoveLabels (IList indexes, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (indexes, modseq, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously remove a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Removes a set of labels from the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The labels to remove. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// -or- /// No labels were specified. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> RemoveLabelsAsync (IList indexes, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); if (labels.Count == 0) throw new ArgumentException ("No labels were specified.", nameof (labels)); return ModifyLabelsAsync (indexes, modseq, labels, silent ? "-X-GM-LABELS.SILENT" : "-X-GM-LABELS", true, cancellationToken); } /// /// Set the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override IList SetLabels (IList indexes, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); return ModifyLabelsAsync (indexes, modseq, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", false, cancellationToken).GetAwaiter ().GetResult (); } /// /// Asynchronously set the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// /// Sets the labels of the specified messages only if their mod-sequence value is less than the specified value. /// /// The indexes of the messages that were not updated. /// The indexes of the messages. /// The mod-sequence value. /// The labels to set. /// If set to true, no events will be emitted. /// The cancellation token. /// /// is null. /// -or- /// is null. /// /// /// One or more of the is invalid. /// /// /// The has been disposed. /// /// /// The is not connected. /// /// /// The is not authenticated. /// /// /// The is not currently open in read-write mode. /// /// /// The IMAP server does not support the Google Mail Extensions. /// /// /// The operation was canceled via the cancellation token. /// /// /// An I/O error occurred. /// /// /// The server's response contained unexpected tokens. /// /// /// The server replied with a NO or BAD response. /// public override Task> SetLabelsAsync (IList indexes, ulong modseq, IList labels, bool silent, CancellationToken cancellationToken = default (CancellationToken)) { if (labels == null) throw new ArgumentNullException (nameof (labels)); return ModifyLabelsAsync (indexes, modseq, labels, silent ? "X-GM-LABELS.SILENT" : "X-GM-LABELS", true, cancellationToken); } } }