| @@ -93,7 +93,6 @@ namespace Discord | |||||
| { | { | ||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
| if (text == null) throw new ArgumentNullException(nameof(text)); | if (text == null) throw new ArgumentNullException(nameof(text)); | ||||
| if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| CheckReady(); | CheckReady(); | ||||
| return SendMessage(channel, text, false); | return SendMessage(channel, text, false); | ||||
| @@ -103,7 +102,6 @@ namespace Discord | |||||
| { | { | ||||
| if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
| if (text == null) throw new ArgumentNullException(nameof(text)); | if (text == null) throw new ArgumentNullException(nameof(text)); | ||||
| if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| CheckReady(); | CheckReady(); | ||||
| return SendMessage(channel, text, false); | return SendMessage(channel, text, false); | ||||
| @@ -113,7 +111,6 @@ namespace Discord | |||||
| { | { | ||||
| if (user == null) throw new ArgumentNullException(nameof(user)); | if (user == null) throw new ArgumentNullException(nameof(user)); | ||||
| if (text == null) throw new ArgumentNullException(nameof(text)); | if (text == null) throw new ArgumentNullException(nameof(text)); | ||||
| if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| CheckReady(); | CheckReady(); | ||||
| var channel = await CreatePMChannel(user).ConfigureAwait(false); | var channel = await CreatePMChannel(user).ConfigureAwait(false); | ||||
| @@ -122,10 +119,10 @@ namespace Discord | |||||
| private async Task<Message> SendMessage(Channel channel, string text, bool isTextToSpeech) | private async Task<Message> SendMessage(Channel channel, string text, bool isTextToSpeech) | ||||
| { | { | ||||
| Message msg; | Message msg; | ||||
| var userIds = !channel.IsPrivate ? Mention.GetUserIds(text).Distinct() : new string[0]; | |||||
| var server = channel.Server; | |||||
| if (Config.UseMessageQueue) | if (Config.UseMessageQueue) | ||||
| { | { | ||||
| var channelIds = !channel.IsPrivate ? Mention.GetChannelIds(text).Distinct() : new string[0]; | |||||
| var nonce = GenerateNonce(); | var nonce = GenerateNonce(); | ||||
| msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _userId); | msg = _messages.GetOrAdd("nonce_" + nonce, channel.Id, _userId); | ||||
| var currentUser = msg.User; | var currentUser = msg.User; | ||||
| @@ -140,21 +137,21 @@ namespace Discord | |||||
| msg.Nonce = nonce; | msg.Nonce = nonce; | ||||
| msg.IsQueued = true; | msg.IsQueued = true; | ||||
| //IsPrivate check is already done earlier | |||||
| msg.MentionedUsers = userIds | |||||
| .Select(x => _users[x, channel.Server.Id]) | |||||
| .Where(x => x != null) | |||||
| .ToArray(); | |||||
| msg.MentionedChannels = channelIds | |||||
| .Select(x => _channels[x]) | |||||
| .Where(x => x != null && x.Server == channel.Server) | |||||
| .ToArray(); | |||||
| if (text.Length > MaxMessageSize) | |||||
| throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| _pendingMessages.Enqueue(msg); | _pendingMessages.Enqueue(msg); | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| var model = await _api.SendMessage(channel.Id, text, userIds, null, isTextToSpeech).ConfigureAwait(false); | |||||
| var mentionedUsers = new List<User>(); | |||||
| if (!channel.IsPrivate) | |||||
| text = Mention.CleanUserMentions(this, server, text, mentionedUsers); | |||||
| if (text.Length > MaxMessageSize) | |||||
| throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| var model = await _api.SendMessage(channel.Id, text, mentionedUsers.Select(x => x.Id), null, isTextToSpeech).ConfigureAwait(false); | |||||
| msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id); | msg = _messages.GetOrAdd(model.Id, channel.Id, model.Author.Id); | ||||
| msg.Update(model); | msg.Update(model); | ||||
| RaiseMessageSent(msg); | RaiseMessageSent(msg); | ||||
| @@ -179,13 +176,17 @@ namespace Discord | |||||
| { | { | ||||
| if (message == null) throw new ArgumentNullException(nameof(message)); | if (message == null) throw new ArgumentNullException(nameof(message)); | ||||
| if (text == null) throw new ArgumentNullException(nameof(text)); | if (text == null) throw new ArgumentNullException(nameof(text)); | ||||
| if (text.Length > MaxMessageSize) throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| CheckReady(); | CheckReady(); | ||||
| if (text != null && text.Length > MaxMessageSize) | |||||
| text = text.Substring(0, MaxMessageSize); | |||||
| var channel = message.Channel; | |||||
| var mentionedUsers = new List<User>(); | |||||
| if (!channel.IsPrivate) | |||||
| text = Mention.CleanUserMentions(this, channel.Server, text, mentionedUsers); | |||||
| if (text.Length > MaxMessageSize) | |||||
| throw new ArgumentOutOfRangeException(nameof(text), $"Message must be {MaxMessageSize} characters or less."); | |||||
| return _api.EditMessage(message.Id, message.Channel.Id, text, Mention.GetUserIds(text)); | |||||
| return _api.EditMessage(message.Id, message.Channel.Id, text, mentionedUsers.Select(x => x.Id)); | |||||
| } | } | ||||
| /// <summary> Deletes the provided message. </summary> | /// <summary> Deletes the provided message. </summary> | ||||
| @@ -8,6 +8,7 @@ namespace Discord | |||||
| { | { | ||||
| private static readonly Regex _userRegex = new Regex(@"<@([0-9]+?)>", RegexOptions.Compiled); | private static readonly Regex _userRegex = new Regex(@"<@([0-9]+?)>", RegexOptions.Compiled); | ||||
| private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+?)>", RegexOptions.Compiled); | private static readonly Regex _channelRegex = new Regex(@"<#([0-9]+?)>", RegexOptions.Compiled); | ||||
| private static readonly Regex _roleRegex = new Regex(@"@everyone", RegexOptions.Compiled); | |||||
| /// <summary> Returns the string used to create a user mention. </summary> | /// <summary> Returns the string used to create a user mention. </summary> | ||||
| public static string User(User user) | public static string User(User user) | ||||
| @@ -19,45 +20,45 @@ namespace Discord | |||||
| public static string Everyone() | public static string Everyone() | ||||
| => $"@everyone"; | => $"@everyone"; | ||||
| internal static string ConvertToNames(DiscordClient client, Server server, string text) | |||||
| internal static string CleanUserMentions(DiscordClient client, Server server, string text, List<User> users = null) | |||||
| { | { | ||||
| text = _userRegex.Replace(text, new MatchEvaluator(e => | |||||
| return _userRegex.Replace(text, new MatchEvaluator(e => | |||||
| { | { | ||||
| string id = e.Value.Substring(2, e.Value.Length - 3); | string id = e.Value.Substring(2, e.Value.Length - 3); | ||||
| var user = client.Users[id, server?.Id]; | var user = client.Users[id, server?.Id]; | ||||
| if (user != null) | if (user != null) | ||||
| { | |||||
| if (users != null) | |||||
| users.Add(user); | |||||
| return '@' + user.Name; | return '@' + user.Name; | ||||
| } | |||||
| else //User not found | else //User not found | ||||
| return '@' + e.Value; | return '@' + e.Value; | ||||
| })); | })); | ||||
| if (server != null) | |||||
| } | |||||
| internal static string CleanChannelMentions(DiscordClient client, Server server, string text, List<Channel> channels = null) | |||||
| { | |||||
| return _channelRegex.Replace(text, new MatchEvaluator(e => | |||||
| { | { | ||||
| text = _channelRegex.Replace(text, new MatchEvaluator(e => | |||||
| string id = e.Value.Substring(2, e.Value.Length - 3); | |||||
| var channel = client.Channels[id]; | |||||
| if (channel != null && channel.Server.Id == server.Id) | |||||
| { | { | ||||
| string id = e.Value.Substring(2, e.Value.Length - 3); | |||||
| var channel = client.Channels[id]; | |||||
| if (channel != null && channel.Server.Id == server.Id) | |||||
| return '#' + channel.Name; | |||||
| else //Channel not found | |||||
| if (channels != null) | |||||
| channels.Add(channel); | |||||
| return '#' + channel.Name; | |||||
| } | |||||
| else //Channel not found | |||||
| return '#' + e.Value; | return '#' + e.Value; | ||||
| })); | |||||
| } | |||||
| return text; | |||||
| } | |||||
| internal static IEnumerable<string> GetUserIds(string text) | |||||
| { | |||||
| return _userRegex.Matches(text) | |||||
| .OfType<Match>() | |||||
| .Select(x => x.Groups[1].Value) | |||||
| .Where(x => x != null); | |||||
| })); | |||||
| } | } | ||||
| internal static IEnumerable<string> GetChannelIds(string text) | |||||
| internal static string CleanRoleMentions(DiscordClient client, Server server, string text, List<Role> roles = null) | |||||
| { | { | ||||
| return _channelRegex.Matches(text) | |||||
| .OfType<Match>() | |||||
| .Select(x => x.Groups[1].Value) | |||||
| .Where(x => x != null); | |||||
| return _roleRegex.Replace(text, new MatchEvaluator(e => | |||||
| { | |||||
| roles.Add(server.EveryoneRole); | |||||
| return e.Value; | |||||
| })); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -90,9 +90,7 @@ namespace Discord | |||||
| Height = height; | Height = height; | ||||
| } | } | ||||
| } | } | ||||
| private string _cleanText; | |||||
| /// <summary> Returns the local unique identifier for this message. </summary> | /// <summary> Returns the local unique identifier for this message. </summary> | ||||
| public string Nonce { get; internal set; } | public string Nonce { get; internal set; } | ||||
| @@ -110,8 +108,7 @@ namespace Discord | |||||
| /// <summary> Returns the raw content of this message as it was received from the server.. </summary> | /// <summary> Returns the raw content of this message as it was received from the server.. </summary> | ||||
| public string RawText { get; private set; } | public string RawText { get; private set; } | ||||
| /// <summary> Returns the content of this message with any special references such as mentions converted. </summary> | /// <summary> Returns the content of this message with any special references such as mentions converted. </summary> | ||||
| /// <remarks> This value is lazy loaded and only processed on first request. Each subsequent request will pull from cache. </remarks> | |||||
| public string Text => _cleanText != null ? _cleanText : (_cleanText = Mention.ConvertToNames(_client, Server, RawText)); | |||||
| public string Text { get; private set; } | |||||
| /// <summary> Returns the timestamp for when this message was sent. </summary> | /// <summary> Returns the timestamp for when this message was sent. </summary> | ||||
| public DateTime Timestamp { get; private set; } | public DateTime Timestamp { get; private set; } | ||||
| /// <summary> Returns the timestamp for when this message was last edited. </summary> | /// <summary> Returns the timestamp for when this message was last edited. </summary> | ||||
| @@ -131,6 +128,10 @@ namespace Discord | |||||
| [JsonIgnore] | [JsonIgnore] | ||||
| public IEnumerable<Channel> MentionedChannels { get; internal set; } | public IEnumerable<Channel> MentionedChannels { get; internal set; } | ||||
| /// <summary> Returns a collection of all roles mentioned in this message. </summary> | |||||
| [JsonIgnore] | |||||
| public IEnumerable<Role> MentionedRoles { get; internal set; } | |||||
| /// <summary> Returns the server containing the channel this message was sent to. </summary> | /// <summary> Returns the server containing the channel this message was sent to. </summary> | ||||
| [JsonIgnore] | [JsonIgnore] | ||||
| public Server Server => _channel.Value.Server; | public Server Server => _channel.Value.Server; | ||||
| @@ -220,18 +221,23 @@ namespace Discord | |||||
| } | } | ||||
| if (model.Content != null) | if (model.Content != null) | ||||
| { | { | ||||
| RawText = model.Content; | |||||
| _cleanText = null; | |||||
| if (!Channel.IsPrivate) | |||||
| var server = Server; | |||||
| string text = model.Content; | |||||
| RawText = text; | |||||
| //var mentionedUsers = new List<User>(); | |||||
| var mentionedChannels = new List<Channel>(); | |||||
| var mentionedRoles = new List<Role>(); | |||||
| text = Mention.CleanUserMentions(_client, server, text/*, mentionedUsers*/); | |||||
| if (server != null) | |||||
| { | { | ||||
| MentionedChannels = Mention.GetChannelIds(model.Content) | |||||
| .Select(x => _client.Channels[x]) | |||||
| .Where(x => x.Server == Channel.Server) | |||||
| .ToArray(); | |||||
| text = Mention.CleanChannelMentions(_client, server, text, mentionedChannels); | |||||
| text = Mention.CleanRoleMentions(_client, server, text, mentionedRoles); | |||||
| } | } | ||||
| else | |||||
| MentionedChannels = new Channel[0]; | |||||
| //MentionedUsers = mentionedUsers; | |||||
| MentionedChannels = mentionedChannels; | |||||
| MentionedRoles = mentionedRoles; | |||||
| } | } | ||||
| } | } | ||||