public async Task <IResponsiveMessageResponse> GetResponseAsync(ICommandContext context, Messaging.IMessage message, bool allowCancellation = true)
        {
            ResponsiveMessageInfo info = await SendMessageAndReturnInfoAsync(context, message, allowCancellation);

            IResponsiveMessageResponse response = new ResponseMessageResponse(null, true);

            if (info != null)
            {
                // Block until we get a response.

                info.Waiter = new ManualResetEvent(false);
                info.Waiter.WaitOne();

                response = info.Response;

                if (response is null)
                {
                    response = new ResponseMessageResponse(null, true);
                }

                if (response.Canceled)
                {
                    await context.Channel.SendMessageAsync(embed : EmbedUtilities.BuildInfoEmbed("The command has been canceled.").ToDiscordEmbed());
                }
            }

            return(response);
        }
        public async Task <bool> HandleMessageAsync(IMessage message)
        {
            ResponsiveMessageInfo info = messages.GetOrDefault(message.Author.Id);

            if (info != null && message.Channel.Id == info.Context.Channel.Id)
            {
                Messaging.IMessage responseMessage = new Message(message.Content)
                {
                    Attachments = message.Attachments.Select(attachment => new Messaging.Attachment()
                    {
                        Url = attachment.Url, Filename = attachment.Filename
                    })
                };

                info.Response = new ResponseMessageResponse(responseMessage, info.AllowCancellation && message.Content.Equals(CancellationString, StringComparison.OrdinalIgnoreCase));

                RemoveMessageInfo(message.Author.Id);

                info.Waiter.Set();

                return(await Task.FromResult(true));
            }

            return(await Task.FromResult(false));
        }
        private async Task <ResponsiveMessageInfo> SendMessageAndReturnInfoAsync(ICommandContext context, Messaging.IMessage message, bool allowCancellation)
        {
            ResponsiveMessageInfo info = null;

            if (message != null)
            {
                if (allowCancellation)
                {
                    message.Text += $"\nTo cancel, reply with \"{CancellationString}\".";
                }

                IUserMessage sentMessage = await context.Channel.SendMessageAsync(message?.Text, false, message?.Embed?.ToDiscordEmbed());

                if (messages.Count() >= MaxResponsiveMessages)
                {
                    // Remove the oldest message.

                    ulong oldestMessageUserId = messages
                                                .OrderBy(pair => pair.Value.Context.Message.Timestamp)
                                                .Select(pair => pair.Key)
                                                .First();

                    RemoveMessageInfo(oldestMessageUserId);
                }

                info = new ResponsiveMessageInfo {
                    AllowCancellation = allowCancellation,
                    Context           = context
                };

                if (messages.TryAdd(context.User.Id, info))
                {
                    return(info);
                }
            }

            return(info);
        }