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