예제 #1
0
 protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
 {
     if (isEdited)
     {
         // find and change!
         lock (MessageList)
         {
             var node = MessageList.Find(m => m.ID == message.ID);
             if (node == null)
             {
                 // I guess I don't remember this one anymore
                 return;
             }
             node.Value = message;
         }
     }
     else
     {
         lock (MessageList)
         {
             MessageList.AddFirst(message);
             while (MessageList.Count > Config.Backlog)
             {
                 MessageList.RemoveLast();
             }
         }
     }
 }
예제 #2
0
 public MessageToDistribute(bool isPartOfInitialSalvo, bool isEdited, bool isBanned, ChatboxMessage message)
 {
     IsPartOfInitialSalvo = isPartOfInitialSalvo;
     IsEdited             = isEdited;
     IsBanned             = isBanned;
     Message = message;
 }
예제 #3
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false,
                                                      bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || isBanned)
            {
                return;
            }

            var body = message.BodyBBCode;

            if (body == "!lastlink")
            {
                if (_lastLink == null)
                {
                    Connector.SendMessage("No last link!");
                }
                else
                {
                    PostLinkInfo(new [] { _lastLink });
                }
                return;
            }
            if (body == "!lasticon")
            {
                if (_lastIcon == null)
                {
                    Connector.SendMessage("No last icon!");
                }
                else
                {
                    PostLinkInfo(new [] { _lastIcon });
                }
            }

            // find all the links
            var dom   = message.BodyDom;
            var links = FindLinks(dom);
            var icons = FindIcons(dom);

            // store the new "last link"
            if (links.Count > 0)
            {
                _lastLink = links[links.Count - 1];
            }
            if (icons.Count > 0)
            {
                _lastIcon = icons[icons.Count - 1];
            }

            // respond?
            if (body.StartsWith("!link "))
            {
                PostLinkInfo(links);
            }
            else if (body.StartsWith("!icon "))
            {
                PostLinkInfo(icons);
            }
        }
예제 #4
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || isBanned)
            {
                return;
            }

            var body = message.BodyBBCode;

            if (!IsDownRegex.Match(body).Success)
            {
                return;
            }

            var client = new WebClient
            {
                Encoding = Encoding.UTF8
            };
            var response = client.DownloadString(_config.ApiUrl);
            var pieces   = response.Split(' ');

            if (pieces.Length != 3)
            {
                Logger.DebugFormat(
                    "unexpected server answer {0} for nickname {1}",
                    Util.LiteralString(response),
                    message.UserName
                    );
                Connector.SendMessage(string.Format(PickRandom(_config.UnknownMessages), message.UserName));
                return;
            }

            var status               = pieces[0];
            var sinceTimeString      = pieces[1];
            var lastUpdateTimeString = pieces[2];

            var since      = FormatDateTime(Util.UnixTimestampStringToLocalDateTime(sinceTimeString));
            var lastUpdate = FormatDateTime(Util.UnixTimestampStringToLocalDateTime(lastUpdateTimeString));

            IList <string> pickOne = _config.UnknownMessages;

            if (status == "0")
            {
                pickOne = _config.UpMessages;
            }
            else if (status == "1")
            {
                pickOne = _config.DownMessages;
            }

            var outgoing = PickRandom(pickOne);

            Connector.SendMessage(string.Format(
                                      outgoing,
                                      message.UserName,
                                      since,
                                      lastUpdate
                                      ));
        }
예제 #5
0
        protected void PotentialDictSpy(ChatboxMessage message)
        {
            var spyDictMatch = SpyDictTrigger.Match(message.BodyBBCode);

            if (!spyDictMatch.Success)
            {
                return;
            }

            var userLevel  = GetUserLevel(message.UserName);
            var salutation = userLevel.ToString();

            if (userLevel != UserLevel.Spymaster)
            {
                SendInsufficientRankMessage(salutation, message.UserName);
                return;
            }

            var wordList   = spyDictMatch.Groups[1].Value.Trim();
            var origString = spyDictMatch.Groups[2].Value.Trim();
            var replString = spyDictMatch.Groups[3].Value.Trim();

            if (!_wordLists.ContainsKey(wordList))
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: Unknown word list [noparse]{2}[/noparse].",
                                          salutation,
                                          message.UserName,
                                          Util.ExpungeNoparse(wordList)
                                          ));
                return;
            }

            long newDictTriggerID;

            using (var ctx = GetNewContext())
            {
                var dictTrig = new DictionaryTrigger
                {
                    OriginalString    = origString,
                    ReplacementString = replString,
                    WordList          = wordList,
                    SpymasterName     = message.UserName
                };
                ctx.DictionaryTriggers.Add(dictTrig);
                ctx.SaveChanges();
                newDictTriggerID = dictTrig.ID;
            }

            Connector.SendMessage(string.Format(
                                      "{0} [noparse]{1}[/noparse]: Done (#{2}).",
                                      salutation,
                                      message.UserName,
                                      newDictTriggerID
                                      ));
        }
예제 #6
0
        protected void SendRandomMotivatorFromList(IList <string> motivatorList, ChatboxMessage requestMessage)
        {
            // pick a motivator
            var index     = _random.Next(motivatorList.Count);
            var motivator = motivatorList[index];

            // personalize
            motivator = string.Format(motivator, requestMessage.UserName);

            // send
            Connector.SendMessage(string.Format("[noparse]{0}[/noparse]: {1}", requestMessage.UserName, motivator));
        }
예제 #7
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || isBanned)
            {
                return;
            }

            var body = message.BodyBBCode.ToLowerInvariant();

            foreach (var verbCategories in _config.VerbsCategoriesMotivators)
            {
                var verbMeUsing = string.Format("!{0} me using ", verbCategories.Key);
                if (body == string.Format("!{0} me", verbCategories.Key))
                {
                    // unite the motivators from all categories
                    var motivatorList = new List <string>();
                    foreach (var motivators in verbCategories.Value.Values)
                    {
                        motivatorList.AddRange(motivators);
                    }
                    SendRandomMotivatorFromList(motivatorList, message);
                    return;
                }
                else if (body.StartsWith(verbMeUsing))
                {
                    var category = body.Substring(verbMeUsing.Length);
                    if (!verbCategories.Value.ContainsKey(category))
                    {
                        Connector.SendMessage(string.Format(
                                                  "[noparse]{0}[/noparse]: I don\u2019t know that category.",
                                                  message.UserName
                                                  ));
                        return;
                    }
                    var motivatorList = verbCategories.Value[category];
                    SendRandomMotivatorFromList(motivatorList, message);
                    return;
                }
                else if (body == string.Format("!how can you {0} me", verbCategories.Key))
                {
                    var categories = verbCategories.Value.Keys.ToList();
                    categories.Sort();
                    var categoriesString = string.Join(", ", categories);
                    Connector.SendMessage(string.Format(
                                              "[noparse]{0}[/noparse]: I can {1} you using {2}.",
                                              message.UserName, verbCategories.Key, categoriesString
                                              ));
                    return;
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Checks whether a new ECHELON trigger is to be added and potentially does so.
        /// </summary>
        protected void PotentialSpy(ChatboxMessage message)
        {
            var spyMatch = SpyTrigger.Match(message.BodyBBCode);

            if (!spyMatch.Success)
            {
                return;
            }

            var userLevel  = GetUserLevel(message.UserName);
            var salutation = userLevel.ToString();

            if (userLevel != UserLevel.Spymaster)
            {
                SendInsufficientRankMessage(salutation, message.UserName);
                return;
            }

            var username = spyMatch.Groups[1].Success ? spyMatch.Groups[1].Value.Trim().ToLowerInvariant() : null;
            var regex    = spyMatch.Groups[2].Value.Trim();

            long newTriggerID;

            using (var ctx = GetNewContext())
            {
                var trig = new Trigger
                {
                    TargetNameLower = username,
                    Regex           = regex,
                    SpymasterName   = message.UserName
                };
                ctx.Triggers.Add(trig);
                ctx.SaveChanges();
                newTriggerID = trig.Id;
            }

            Connector.SendMessage(string.Format(
                                      "{0} [noparse]{1}[/noparse]: Done (#{2}).",
                                      salutation,
                                      message.UserName,
                                      newTriggerID
                                      ));
        }
예제 #9
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false,
                                                      bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || isBanned)
            {
                return;
            }

            if (message.UserName == Connector.ForumConfig.Username)
            {
                // prevent loops
                return;
            }

            var originalBody = Util.RemoveControlCharactersAndStrip(message.BodyBBCode);
            var newBody      = originalBody;

            foreach (var repl in _config.Replacements)
            {
                // substitute the username in the replacement string
                var replacementStringWithUser = repl.ReplacementString.Replace("{{{username}}}", message.UserName);
                newBody = repl.Regex.Replace(newBody, replacementStringWithUser);
            }

            if (newBody == originalBody)
            {
                return;
            }

            var thisProbabilityValue = _random.NextDouble() * 100.0;

            if (thisProbabilityValue < _config.ProbabilityPercent)
            {
                Logger.DebugFormat("{0:F2} < {1:F2}; posting {2}", thisProbabilityValue, _config.ProbabilityPercent, newBody);
                Connector.SendMessage(newBody);
            }
            else
            {
                Logger.DebugFormat("{0:F2} >= {1:F2}; not posting {2}", thisProbabilityValue, _config.ProbabilityPercent, newBody);
            }
        }
예제 #10
0
        protected void PotentialDeliverRequest(ChatboxMessage message)
        {
            var body  = message.BodyBBCode;
            var match = DeliverTrigger.Match(body);

            if (!match.Success)
            {
                return;
            }

            // overflow avoidance
            if (match.Groups[1].Length > 3)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: I am absolutely not delivering that many messages at once.",
                                          message.UserName
                                          ));
                return;
            }
            var fetchCount      = int.Parse(match.Groups[1].Value);
            var lowerSenderName = message.UserName.ToLowerInvariant();

            List <MessageOnRetainer> messages;
            int messagesLeft;

            using (var ctx = GetNewContext())
            {
                // get the messages
                messages = ctx.MessagesOnRetainer
                           .Where(m => m.RecipientFolded == lowerSenderName)
                           .OrderBy(m => m.ID)
                           .Take(fetchCount)
                           .ToList()
                ;

                // delete them
                ctx.MessagesOnRetainer.RemoveRange(messages);
                ctx.SaveChanges();

                // check how many are left
                messagesLeft = ctx.MessagesOnRetainer
                               .Count(m => m.RecipientFolded == lowerSenderName)
                ;
            }

            // deliver them
            if (messages.Count > 0)
            {
                Connector.SendMessage(string.Format(
                                          "Delivering {0} {1} for [noparse]{2}[/noparse]!",
                                          messages.Count,
                                          messages.Count == 1 ? "message" : "messages",
                                          message.UserName
                                          ));
                foreach (var msg in messages)
                {
                    Logger.DebugFormat(
                        "delivering {0}'s retained message {1} to {2} as part of a chunk",
                        Util.LiteralString(msg.SenderOriginal),
                        Util.LiteralString(msg.Body),
                        Util.LiteralString(message.UserName)
                        );
                    Connector.SendMessage(string.Format(
                                              "{0} <[noparse]{1}[/noparse]> {2}",
                                              FormatUtcTimestampFromDatabase(msg.ID, msg.Timestamp),
                                              msg.SenderOriginal,
                                              msg.Body
                                              ));
                }
            }

            // output remaining messages count
            if (messagesLeft == 0)
            {
                if (messages.Count > 0)
                {
                    Connector.SendMessage(string.Format(
                                              "[noparse]{0}[/noparse] has no more messages left to deliver!",
                                              message.UserName
                                              ));
                }
                else
                {
                    Connector.SendMessage(string.Format(
                                              "[noparse]{0}[/noparse] has no messages to deliver!",
                                              message.UserName
                                              ));
                }
            }
            else
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse] has {1} {2} left to deliver!",
                                          message.UserName,
                                          messagesLeft,
                                          (messagesLeft == 1) ? "message" : "messages"
                                          ));
            }
        }
예제 #11
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isEdited || isPartOfInitialSalvo || isBanned)
            {
                // do nothing
                return;
            }

            if (message.UserName == Connector.ForumConfig.Username)
            {
                // ignore my own messages
                return;
            }

            var body = message.BodyBBCode;

            if (body == "!stfu")
            {
                // check for ban
                using (var context = GetNewContext())
                {
                    var ban = context.Bans.Find(message.UserName);
                    if (ban != null)
                    {
                        if (!ban.Deadline.HasValue)
                        {
                            Logger.DebugFormat("{0} wants to shut me up but they're permabanned", message.UserName);
                            SendSnark(message.UserName);
                            return;
                        }
                        else if (ban.Deadline.Value > DateTime.Now)
                        {
                            Logger.DebugFormat("{0} wants to shut me up but they're banned until {1}", message.UserName, ban.Deadline.Value);
                            SendSnark(message.UserName);
                            return;
                        }
                    }

                    // no ban -- STFU
                    Logger.InfoFormat("{0} shut me up for {1} minutes", message.UserName, _config.Duration / 60);
                    _whoShutMeUpLast       = message.UserName;
                    Connector.StfuDeadline = DateTime.Now.AddSeconds(_config.Duration);
                }
            }
            else if (body == "!unstfu")
            {
                if (!_config.Admins.Contains(message.UserName))
                {
                    Logger.DebugFormat("{0} wants to un-stfu me, but they aren't an admin", message.UserName);
                    return;
                }

                Logger.InfoFormat("{0} un-stfu-ed me", message.UserName);
                Connector.StfuDeadline = null;
                Connector.SendMessage("I can speak again!");
            }
            else if (body.StartsWith("!stfuban "))
            {
                if (!_config.Admins.Contains(message.UserName))
                {
                    Logger.DebugFormat("{0} wants to ban someone but they aren't an admin", message.UserName);
                    SendSnark(message.UserName);
                    return;
                }

                var bodyRest  = body.Substring(("!stfuban ").Length);
                var nextSpace = bodyRest.IndexOf(' ');
                if (nextSpace == -1)
                {
                    Connector.SendMessage("Usage: !stfuban timespec username");
                    return;
                }

                var timeSpec    = bodyRest.Substring(0, nextSpace);
                var banThisUser = bodyRest.Substring(nextSpace + 1);

                var      seconds = DurationStringToSeconds(timeSpec);
                DateTime?deadline;
                if (seconds == 0)
                {
                    Connector.SendMessage("Invalid timespec!");
                    return;
                }
                else if (seconds == -1)
                {
                    deadline = null;
                }
                else
                {
                    deadline = DateTime.Now.AddSeconds(seconds);
                }

                // insert the ban into the database
                using (var context = GetNewContext())
                {
                    var runningBan = context.Bans.Find(banThisUser);
                    if (runningBan != null)
                    {
                        runningBan.Deadline = deadline;
                        runningBan.Banner   = message.UserName;
                    }
                    else
                    {
                        runningBan = new Ban
                        {
                            BannedUser = banThisUser,
                            Deadline   = deadline,
                            Banner     = message.UserName
                        };
                        context.Bans.Add(runningBan);
                    }
                    context.SaveChanges();
                }

                if (_whoShutMeUpLast == banThisUser)
                {
                    // un-STFU immediately
                    Connector.StfuDeadline = null;
                }

                Logger.InfoFormat("{0} banned {1} from using !stfu for {2}", message.UserName, banThisUser, timeSpec);
                if (!deadline.HasValue)
                {
                    Connector.SendMessage(string.Format("Alright! Banning {0} from using the !stfu function.", banThisUser), bypassStfu: true);
                }
                else
                {
                    Connector.SendMessage(string.Format("Alright! Banning {0} from using the !stfu function until {1}.", banThisUser, deadline.Value), bypassStfu: true);
                }
            }
            else if (body.StartsWith("!stfuunban "))
            {
                if (!_config.Admins.Contains(message.UserName))
                {
                    Logger.DebugFormat("{0} wants to unban someone but they aren't an admin", message.UserName);
                    SendSnark(message.UserName);
                    return;
                }

                var unbanThisUser = body.Substring(("!stfuunban ").Length);

                using (var context = GetNewContext())
                {
                    var runningBan = context.Bans.Find(unbanThisUser);
                    if (runningBan == null)
                    {
                        Connector.SendMessage(string.Format("{0} isn't even banned...?", unbanThisUser));
                    }
                    else
                    {
                        context.Bans.Remove(runningBan);
                        context.SaveChanges();
                        Connector.SendMessage(string.Format("Alright, {0} may use !stfu again.", unbanThisUser));
                    }
                }
            }
        }
예제 #12
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || isBanned)
            {
                return;
            }

            var body  = message.BodyBBCode;
            var match = SeenRegex.Match(body);

            if (!match.Success)
            {
                return;
            }

            var nicknames = match.Groups[1].Value.Split(';').Select(n => n.Trim().Replace("[/noparse]", "")).Where(n => n.Length > 0).ToList();

            if (nicknames.Count == 0)
            {
                return;
            }

            var nicknamesInfos = new Dictionary <string, SeenInfo>();

            foreach (var nickname in nicknames)
            {
                var urlEncodedNickname = Util.UrlEncode(nickname, Util.Utf8NoBom, spaceAsPlus: true);
                var callUrl            = new Uri(string.Format(_config.ApiUrlTemplate, urlEncodedNickname));

                var client = new WebClient();
                if (_config.ApiUsername != null || _config.ApiPassword != null)
                {
                    client.Credentials = new NetworkCredential(_config.ApiUsername ?? "", _config.ApiPassword ?? "");
                }
                var response = client.DownloadString(callUrl);

                if (response == "NULL")
                {
                    nicknamesInfos[nickname] = null;
                    continue;
                }
                var pieces = response.Split(' ');
                if (pieces.Length != 3)
                {
                    Logger.WarnFormat("unexpected server answer {0} for nickname {1}", Util.LiteralString(response), Util.LiteralString(nickname));
                    continue;
                }

                nicknamesInfos[nickname] = new SeenInfo
                {
                    Timestamp = Util.UnixTimestampStringToLocalDateTime(pieces[0]),
                    MessageID = Util.MaybeParseLong(pieces[1]),
                    Epoch     = Util.MaybeParseLong(pieces[2])
                };
            }

            if (nicknames.Count == 1)
            {
                // single-user request
                var nickname = nicknames[0];
                var info     = nicknamesInfos[nickname];

                if (info == null)
                {
                    Connector.SendMessage(string.Format(
                                              "{0}: The great and powerful [i]signanz[/i] doesn't remember seeing [i]{1}[/i].",
                                              Connector.EscapeOutogingText(message.UserName),
                                              Connector.EscapeOutogingText(nickname)
                                              ));
                }
                else if (!info.Timestamp.HasValue)
                {
                    Connector.SendMessage(string.Format(
                                              "{0}: The great and powerful [i]signanz[/i]'s answer confused me\u2014sorry!",
                                              Connector.EscapeOutogingText(message.UserName)
                                              ));
                }
                else
                {
                    var timestampString = FormatDateTime(info.Timestamp.Value);
                    if (_config.ArchiveLinkTemplate != null && info.MessageID.HasValue && info.Epoch.HasValue)
                    {
                        timestampString += string.Format(
                            " ([url={0}]\u2192 archive[/url])",
                            string.Format(
                                _config.ArchiveLinkTemplate,
                                info.MessageID.Value,
                                info.Epoch.Value
                                )
                            );
                    }
                    Connector.SendMessage(string.Format(
                                              "{0}: The last time the great and powerful [i]signanz[/i] saw [i]{1}[/i] was {2}.",
                                              Connector.EscapeOutogingText(message.UserName),
                                              Connector.EscapeOutogingText(nickname),
                                              timestampString
                                              ));
                }
            }
            else
            {
                // multi-nick request
                var responseBits = new List <string>();
                foreach (var nickname in nicknames)
                {
                    string text;
                    var    info = nicknamesInfos[nickname];
                    if (info == null)
                    {
                        text = "never";
                    }
                    else if (!info.Timestamp.HasValue)
                    {
                        text = "o_O";
                    }
                    else
                    {
                        text = FormatDateTime(info.Timestamp.Value);
                        if (_config.ArchiveLinkTemplate != null && info.MessageID.HasValue && info.Epoch.HasValue)
                        {
                            text += string.Format(
                                " ([url={0}]\u2192[/url])",
                                string.Format(
                                    _config.ArchiveLinkTemplate,
                                    info.MessageID.Value,
                                    info.Epoch.Value
                                    )
                                );
                        }
                    }

                    responseBits.Add(string.Format(
                                         "[i]{0}[/i]: {1}",
                                         Connector.EscapeOutogingText(nickname),
                                         text
                                         ));
                }

                Connector.SendMessage(string.Format(
                                          "{0}: The great and powerful [i]signanz[/i] saw: {1}",
                                          message.UserName,
                                          string.Join(", ", responseBits)
                                          ));
            }
        }
예제 #13
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isEdited || isPartOfInitialSalvo || message.UserName == Connector.ForumConfig.Username)
            {
                return;
            }

            if (!isBanned)
            {
                PotentialStats(message);
                PotentialStatsRank(message);

                PotentialSpy(message);
                PotentialModifySpy(message);
                PotentialDeleteSpy(message);

                PotentialDictSpy(message);
                PotentialModifyDictSpy(message);
                PotentialDeleteDictSpy(message);
            }

            // spy on messages from banned users too

            var lowerSenderName = message.UserName.ToLowerInvariant();
            var bodyWords       = RemoveNonWord(message.Body).Split(' ');

            using (var ctx = GetNewContext())
            {
                // standard triggers
                var relevantTriggers = ctx.Triggers.Where(t => !t.Deactivated && (t.TargetNameLower == null || t.TargetNameLower == lowerSenderName));
                foreach (var trigger in relevantTriggers)
                {
                    var re = trigger.Regex;
                    if (!_regexCache.ContainsKey(re))
                    {
                        _regexCache[re] = new Regex(re);
                    }

                    if (!_regexCache[re].IsMatch(message.BodyBBCode))
                    {
                        continue;
                    }

                    // incident!
                    var inc = new Incident
                    {
                        TriggerId       = trigger.Id,
                        MessageId       = message.ID,
                        Timestamp       = DateTime.UtcNow.ToUniversalTimeForDatabase(),
                        PerpetratorName = message.UserName.ToLowerInvariant(),
                        Expunged        = false
                    };
                    ctx.Incidents.Add(inc);
                }
                ctx.SaveChanges();

                // dictionary triggers
                var relevantDictTriggers = ctx.DictionaryTriggers.Where(t => !t.Deactivated);
                foreach (var dictTrigger in relevantDictTriggers)
                {
                    var wordSet = _wordLists[dictTrigger.WordList];

                    foreach (var word in bodyWords)
                    {
                        var lowercaseWord = word.ToLower();

                        // word must contain the "from" substring
                        if (lowercaseWord.IndexOf(dictTrigger.OriginalString) == -1)
                        {
                            // doesn't
                            continue;
                        }

                        // is the word in the dictionary?
                        if (wordSet.Contains(lowercaseWord))
                        {
                            // it is
                            continue;
                        }

                        // correct the word
                        var corrected      = word.Replace(dictTrigger.OriginalString, dictTrigger.ReplacementString);
                        var correctedLower = corrected.ToLower();

                        // is the corrected word in the dictionary?
                        if (!wordSet.Contains(correctedLower))
                        {
                            // no
                            continue;
                        }

                        // count it as an incident
                        var dictIncident = new DictionaryIncident
                        {
                            TriggerID       = dictTrigger.ID,
                            MessageID       = message.ID,
                            Timestamp       = DateTime.UtcNow.ToUniversalTimeForDatabase(),
                            PerpetratorName = message.UserName.ToLowerInvariant(),
                            OriginalWord    = word,
                            CorrectedWord   = corrected,
                            Expunged        = false
                        };
                        ctx.DictionaryIncidents.Add(dictIncident);
                    }
                }
                ctx.SaveChanges();
            }
        }
예제 #14
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || isBanned)
            {
                return;
            }

            if (message.UserName == Connector.ForumConfig.Username)
            {
                return;
            }

            var body  = RemoveNonWord(message.Body);
            var words = body.Split(' ');

            var correctedWords = new List <string>();

            foreach (var item in _config.Items)
            {
                var wordSet = _wordLists[item.WordListFilename];

                foreach (var word in words)
                {
                    var lowercaseWord = word.ToLower();

                    // word must contain the "from" substring
                    if (lowercaseWord.IndexOf(item.From) == -1)
                    {
                        // doesn't
                        continue;
                    }

                    // is the word in the dictionary?
                    if (wordSet.Contains(lowercaseWord))
                    {
                        // it is
                        continue;
                    }

                    // correct the word
                    var corrected      = word.Replace(item.From, item.To);
                    var correctedLower = corrected.ToLower();

                    // is the corrected word in the dictionary?
                    if (wordSet.Contains(correctedLower))
                    {
                        // yes; format and add it to the corrected words list
                        correctedWords.Add(string.Format(_config.CorrectedWordFormat, corrected));
                    }
                }
            }

            if (correctedWords.Count == 0)
            {
                return;
            }

            var joined = string.Join(_config.Separator, correctedWords);

            Connector.SendMessage(joined);
        }
예제 #15
0
        protected void PotentialModifyDictSpy(ChatboxMessage message)
        {
            var modSpyDictMatch = ModifySpyDictTrigger.Match(message.BodyBBCode);

            if (!modSpyDictMatch.Success)
            {
                return;
            }

            var userLevel  = GetUserLevel(message.UserName);
            var salutation = userLevel.ToString();

            if (userLevel != UserLevel.Spymaster)
            {
                SendInsufficientRankMessage(salutation, message.UserName);
                return;
            }

            var dictTriggerID = long.Parse(modSpyDictMatch.Groups[1].Value);
            var wordList      = modSpyDictMatch.Groups[2].Value.Trim();
            var origString    = modSpyDictMatch.Groups[3].Value.Trim();
            var replString    = modSpyDictMatch.Groups[4].Value.Trim();

            if (!_wordLists.ContainsKey(wordList))
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: Unknown word list [noparse]{2}[/noparse].",
                                          salutation,
                                          message.UserName,
                                          Util.ExpungeNoparse(wordList)
                                          ));
                return;
            }

            using (var ctx = GetNewContext())
            {
                var dictTrig = ctx.DictionaryTriggers.FirstOrDefault(t => t.ID == dictTriggerID);
                if (dictTrig == null)
                {
                    Connector.SendMessage(string.Format(
                                              "{0} [noparse]{1}[/noparse]: The dictionary trigger with this ID does not exist.",
                                              salutation,
                                              message.UserName
                                              ));
                    return;
                }

                dictTrig.WordList          = wordList;
                dictTrig.OriginalString    = origString;
                dictTrig.ReplacementString = replString;
                dictTrig.SpymasterName     = message.UserName;

                ctx.SaveChanges();
            }

            Connector.SendMessage(string.Format(
                                      "{0} [noparse]{1}[/noparse]: Updated.",
                                      salutation,
                                      message.UserName
                                      ));
        }
예제 #16
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isEdited)
            {
                // don't react to edited messages
                return;
            }

            if (message.UserName.Equals(Connector.ForumConfig.Username, StringComparison.InvariantCulture))
            {
                // the bot itself may not throw things into the bin
                return;
            }

            if (isBanned || _config.Banned.Contains(message.UserName))
            {
                return;
            }

            var body = message.BodyBBCode;

            if (!body.StartsWith("!", StringComparison.InvariantCulture))
            {
                // not a bot trigger; process a possible toss
                HandlePossibleToss(message, body);
            }
            else if (isPartOfInitialSalvo)
            {
                // don't process commands that are part of the initial salvo
            }
            else if (body == "!tonnen")
            {
                Logger.DebugFormat("bin overview request from {0}", message.UserName);

                using (var context = GetNewContext())
                {
                    var bins = context.Bins.Select(b => b.BinName).ToList();

                    if (bins.Count == 0)
                    {
                        Connector.SendMessage("Ich kenne keine Tonnen.");
                    }
                    else if (bins.Count == 1)
                    {
                        Connector.SendMessage("Ich kenne folgende Tonne: '" + bins[0] + "'");
                    }
                    else
                    {
                        bins.Sort();
                        var names = string.Join(", ", bins.Select(x => "'" + x + "'"));
                        Connector.SendMessage("Ich kenne folgende Tonnen: " + names);
                    }
                }
            }
            else if (body.StartsWith("!tonneninhalt "))
            {
                var binName = body.Substring(("!tonneninhalt ").Length);
                Logger.DebugFormat("bin {0} contents request from {1}", binName, message.UserName);

                using (var context = GetNewContext())
                {
                    var bin = context.Bins.FirstOrDefault(b => b.BinName == binName);
                    if (bin == null)
                    {
                        Connector.SendMessage("Diese Tonne kenne ich nicht.");
                        return;
                    }

                    var items = context.BinItems.Where(i => i.Bin.BinName == binName).Select(i => i.Item).ToList();
                    if (items.Count == 0)
                    {
                        Connector.SendMessage("In dieser Tonne befindet sich nichts.");
                    }
                    else if (items.Count == 1)
                    {
                        Connector.SendMessage("In dieser Tonne befindet sich: " + items[0]);
                    }
                    else
                    {
                        items.Sort();
                        var itemString = string.Join(", ", items);
                        Connector.SendMessage("In dieser Tonne befinden sich: " + itemString);
                    }
                }
            }
            else if (body.StartsWith("!entleere "))
            {
                var binName = body.Substring(("!entleere ").Length);
                Logger.DebugFormat("bin {0} emptying request from {1}", binName, message.UserName);

                using (var context = GetNewContext())
                {
                    var bin = context.Bins.FirstOrDefault(b => b.BinName == binName);
                    if (bin == null)
                    {
                        Connector.SendMessage("Diese Tonne kenne ich nicht.");
                        return;
                    }

                    bin.Items.Clear();
                    context.SaveChanges();
                }
            }
            else if (body == "!m\u00fcllabfuhr")
            {
                Logger.DebugFormat("bin removal request from {0}", message.UserName);
                using (var context = GetNewContext())
                {
                    context.DeleteAll <BinItem>();
                    context.DeleteAll <Bin>();
                    context.SaveChanges();
                }
                Connector.SendMessage("Tonnen abgesammelt.");
            }
        }
예제 #17
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isBanned)
            {
                return;
            }

            var body = message.BodyBBCode;

            if (body.Length == 0)
            {
                return;
            }

            // clean out the backlog
            while (_backlog.Count > _config.BacklogSize)
            {
                _backlog.Dequeue();
            }

            if (isEdited)
            {
                // find the message in the backlog and modify it
                var newBacklog = new Queue <BacklogMessage>();
                foreach (var backMessage in _backlog)
                {
                    if (backMessage.MessageID == message.ID)
                    {
                        // store the updated version
                        newBacklog.Enqueue(new BacklogMessage
                        {
                            MessageID = message.ID,
                            Sender    = message.UserName,
                            Body      = message.BodyBBCode
                        });
                    }
                    else
                    {
                        newBacklog.Enqueue(backMessage);
                    }
                }
                _backlog = newBacklog;
            }
            else
            {
                // simply append the message
                _backlog.Enqueue(new BacklogMessage
                {
                    MessageID = message.ID,
                    Sender    = message.UserName,
                    Body      = message.BodyBBCode
                });
            }

            if (isPartOfInitialSalvo)
            {
                // don't post anything just yet
                return;
            }

            // perform accounting
            var messageToSenders = new Dictionary <string, HashSet <string> >();

            foreach (var backMessage in _backlog)
            {
                if (backMessage.Sender == Connector.ForumConfig.Username)
                {
                    // this is my message -- start counting from zero, so to speak
                    messageToSenders[backMessage.Body] = new HashSet <string>();
                }
                else
                {
                    if (!messageToSenders.ContainsKey(backMessage.Body))
                    {
                        messageToSenders[backMessage.Body] = new HashSet <string>();
                    }
                    messageToSenders[backMessage.Body].Add(backMessage.Sender);
                }
            }

            foreach (var messageAndSenders in messageToSenders)
            {
                var msg     = messageAndSenders.Key;
                var senders = messageAndSenders.Value;
                if (senders.Count < _config.TriggerCount)
                {
                    continue;
                }

                Logger.DebugFormat(
                    "bowing to the group pressure of ({0}) sending {1}",
                    string.Join(", ", senders.Select(s => Util.LiteralString(s))),
                    Util.LiteralString(msg)
                    );

                // submit to group pressure
                Connector.SendMessage(msg);

                // fake this message into the backlog to prevent duplicates
                _backlog.Enqueue(new BacklogMessage
                {
                    MessageID = -1,
                    Sender    = Connector.ForumConfig.Username,
                    Body      = msg
                });
            }
        }
예제 #18
0
        protected void HandlePossibleToss(ChatboxMessage message, string body)
        {
            var match = ArrowWasteBinRegex.Match(body);

            if (!match.Success)
            {
                return;
            }

            // a waste bin toss has been found
            var what  = match.Groups[1].Value.Trim();
            var arrow = match.Groups[2].Value;

            var where = match.Groups[3].Value.Trim().ToLowerInvariant();

            if (ArrowRegex.IsMatch(what) || ArrowRegex.IsMatch(where))
            {
                Logger.DebugFormat(
                    "{0} is trying to trick us by throwing {1} into {2}",
                    message.UserName, Util.LiteralString(what), Util.LiteralString(where)
                    );
                return;
            }

            var timestamp = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Unspecified);

            Logger.DebugFormat(
                "{0} tossed {1} into {2} using {3}",
                message.UserName, Util.LiteralString(what), Util.LiteralString(where), Util.LiteralString(arrow)
                );

            using (var context = GetNewContext())
            {
                var bin = context.Bins.Where(x => x.BinName == where).FirstOrDefault();
                if (bin == null)
                {
                    // add the bin
                    bin = new Bin
                    {
                        BinName = where
                    };
                    context.Bins.Add(bin);
                    context.SaveChanges();
                }

                var item = context.BinItems.Where(x => x.Bin.BinName == where && x.Item == what).FirstOrDefault();
                if (item == null)
                {
                    item = new BinItem
                    {
                        Bin       = bin,
                        Thrower   = message.UserName,
                        Arrow     = arrow,
                        Item      = what,
                        Timestamp = timestamp.ToUniversalTimeForDatabase()
                    };
                    context.BinItems.Add(item);
                    context.SaveChanges();
                }
            }
        }
예제 #19
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isPartOfInitialSalvo || isEdited || message.UserName == Connector.ForumConfig.Username)
            {
                return;
            }

            var lowerNickname = message.UserName.ToLowerInvariant();

            if (!isBanned)
            {
                PotentialMessageSend(message);
                PotentialDeliverRequest(message);
                PotentialIgnoreListRequest(message);
                PotentialReplayRequest(message);
            }

            // even banned users get messages; they just can't respond to them

            if (Connector.StfuDeadline.HasValue && Connector.StfuDeadline.Value > DateTime.Now)
            {
                // don't bother just yet
                return;
            }

            // check if the sender should get any messages
            List <Message> messages;

            using (var ctx = GetNewContext())
            {
                messages = ctx.Messages
                           .Where(m => m.RecipientFolded == lowerNickname)
                           .OrderBy(m => m.ID)
                           .ToList()
                ;
                var numberMessagesOnRetainer = ctx.MessagesOnRetainer
                                               .Count(m => m.RecipientFolded == lowerNickname);
                var messagesToDisplay = messages
                                        .Where(m => message.ID - m.ID < 1 || message.ID - m.ID > 2)
                                        .ToList()
                ;

                var retainerText = (numberMessagesOnRetainer > 0)
                    ? string.Format(" (and {0} pending !delivermsg)", numberMessagesOnRetainer)
                    : ""
                ;

                var moveToReplay = true;
                if (messagesToDisplay.Count == 0)
                {
                    // meh
                    // (don't return yet; delete the skipped "responded directly to" messages)
                }
                else if (messagesToDisplay.Count == 1)
                {
                    // one message
                    Logger.DebugFormat(
                        "delivering {0}'s message #{1} {2} to {3}",
                        Util.LiteralString(messagesToDisplay[0].SenderOriginal),
                        messagesToDisplay[0].ID,
                        Util.LiteralString(messagesToDisplay[0].Body),
                        Util.LiteralString(message.UserName)
                        );
                    Connector.SendMessage(string.Format(
                                              "Message for [noparse]{0}[/noparse]{1}! {2} <[noparse]{3}[/noparse]> {4}",
                                              message.UserName,
                                              retainerText,
                                              FormatUtcTimestampFromDatabase(messagesToDisplay[0].ID, messagesToDisplay[0].Timestamp),
                                              messagesToDisplay[0].SenderOriginal,
                                              messagesToDisplay[0].Body
                                              ));
                }
                else if (messagesToDisplay.Count >= _config.TooManyMessages)
                {
                    // use messages instead of messagesToDisplay to put all of them on retainer
                    Logger.DebugFormat(
                        "{0} got {1} messages; putting on retainer",
                        Util.LiteralString(message.UserName),
                        messages.Count
                        );
                    Connector.SendMessage(string.Format(
                                              "{0} new messages for [noparse]{1}[/noparse]{2}! Use \u201c!delivermsg [i]maxnumber[/i]\u201d to get them!",
                                              messages.Count,
                                              message.UserName,
                                              retainerText
                                              ));

                    // put messages on retainer
                    ctx.MessagesOnRetainer.AddRange(messages.Select(m => new MessageOnRetainer(m)));

                    // don't replay!
                    moveToReplay = false;

                    // the content of messages will be cleaned out from ctx.Messages below
                }
                else
                {
                    // multiple but not too many messages
                    Connector.SendMessage(string.Format(
                                              "{0} new messages for [noparse]{1}[/noparse]{2}!",
                                              messagesToDisplay.Count,
                                              message.UserName,
                                              retainerText
                                              ));
                    foreach (var msg in messagesToDisplay)
                    {
                        Logger.DebugFormat(
                            "delivering {0}'s message #{1} {2} to {3} as part of a chunk",
                            Util.LiteralString(msg.SenderOriginal),
                            msg.ID,
                            Util.LiteralString(msg.Body),
                            Util.LiteralString(message.UserName)
                            );
                        Connector.SendMessage(string.Format(
                                                  "{0} <[noparse]{1}[/noparse]> {2}",
                                                  FormatUtcTimestampFromDatabase(msg.ID, msg.Timestamp),
                                                  msg.SenderOriginal,
                                                  msg.Body
                                                  ));
                    }
                    Connector.SendMessage(string.Format(
                                              "[noparse]{0}[/noparse]: Have a nice day!",
                                              message.UserName
                                              ));
                }

                if (moveToReplay)
                {
                    // place the messages on the repeat heap
                    ctx.ReplayableMessages.AddRange(messages.Select(
                                                        m => new ReplayableMessage(m)
                    {
                        Timestamp = m.Timestamp.ToUniversalTimeForDatabase()
                    }
                                                        ));
                }

                // purge the repeat heap if necessary
                var currentReplayables = ctx.ReplayableMessages
                                         .Where(rm => rm.RecipientFolded == lowerNickname)
                                         .OrderBy(rm => rm.ID)
                                         .ToList()
                ;
                if (currentReplayables.Count > _config.MaxMessagesToReplay)
                {
                    var deleteCount = currentReplayables.Count - _config.MaxMessagesToReplay;
                    foreach (var oldReplayable in currentReplayables.Take(deleteCount))
                    {
                        ctx.ReplayableMessages.Remove(oldReplayable);
                    }
                }

                // remove the messages from the delivery queue
                ctx.Messages.RemoveRange(messages);

                // commit
                ctx.SaveChanges();
            }
        }
예제 #20
0
        /// <summary>
        /// Checks whether top-trigger statistics for a user were requested and potentially displays them.
        /// </summary>
        protected void PotentialStatsRank(ChatboxMessage message)
        {
            var rankStatsMatch = StatsRankTrigger.Match(message.BodyBBCode);

            if (!rankStatsMatch.Success)
            {
                return;
            }

            var target      = rankStatsMatch.Groups[1].Value;
            var targetLower = target.ToLowerInvariant();
            var userLevel   = GetUserLevel(message.UserName);
            var salutation  = userLevel.ToString();

            if (userLevel == UserLevel.Terrorist)
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: ECHELON does not provide such information to known terrorists.",
                                          salutation,
                                          message.UserName
                                          ));
                return;
            }

            var triggersAndCounts = new List <TriggerAndCount>();

            using (var ctx = GetNewContext())
            {
                var triggerCounts = ctx.Incidents
                                    .Where(i => !i.Expunged && i.PerpetratorName == targetLower)
                                    .GroupBy(i => i.TriggerId)
                                    .ToList()
                                    .Select(it => new TriggerAndCount
                {
                    TriggerString = "R " + ctx.Triggers.FirstOrDefault(t => t.Id == it.Key).Regex,
                    Count         = it.LongCount()
                })
                                    .OrderByDescending(tac => tac.Count)
                                    .Take(_config.RankCount);

                var dictTriggerCounts = ctx.DictionaryIncidents
                                        .Where(di => !di.Expunged && di.PerpetratorName == targetLower)
                                        .GroupBy(di => di.TriggerID)
                                        .ToList()
                                        .Select(dit => new TriggerAndCount
                {
                    TriggerString = string.Format(
                        "D {0}->{1}",
                        ctx.DictionaryTriggers.FirstOrDefault(dt => dt.ID == dit.Key).OriginalString,
                        ctx.DictionaryTriggers.FirstOrDefault(dt => dt.ID == dit.Key).ReplacementString
                        ),
                    Count = dit.LongCount()
                })
                                        .OrderByDescending(tac => tac.Count)
                                        .Take(_config.RankCount);

                triggersAndCounts.AddRange(triggerCounts);
                triggersAndCounts.AddRange(dictTriggerCounts);
            }

            if (triggersAndCounts.Count == 0)
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: No known incidents for subject [noparse]{2}[/noparse]!",
                                          salutation,
                                          message.UserName,
                                          target
                                          ));
                return;
            }

            triggersAndCounts.Sort();
            triggersAndCounts.Reverse();

            var statsString = string.Join(" || ", triggersAndCounts.Take(_config.RankCount).Select(tac => string.Format("{0}\u00D7{1}", tac.Count, tac.TriggerString)));

            Connector.SendMessage(string.Format(
                                      "{0} [noparse]{1}[/noparse]: Top \u2264{2} incidents for subject [noparse]{3} || {4}[/noparse]",
                                      salutation,
                                      message.UserName,
                                      _config.RankCount,
                                      target,
                                      Util.ExpungeNoparse(statsString)
                                      ));
        }
예제 #21
0
        /// <summary>
        /// Checks whether ECHELON statistics for a user were requested and potentially displays them.
        /// </summary>
        protected void PotentialStats(ChatboxMessage message)
        {
            var statsMatch = StatsTrigger.Match(message.BodyBBCode);

            if (!statsMatch.Success)
            {
                return;
            }

            var target      = statsMatch.Groups[1].Value;
            var targetLower = target.ToLowerInvariant();
            var userLevel   = GetUserLevel(message.UserName);
            var salutation  = userLevel.ToString();

            if (userLevel == UserLevel.Terrorist)
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: ECHELON does not provide such information to known terrorists.",
                                          salutation,
                                          message.UserName
                                          ));
                return;
            }

            long incidentCount;

            using (var ctx = GetNewContext())
            {
                incidentCount  = ctx.Incidents.Where(i => !i.Expunged && i.PerpetratorName == targetLower).LongCount();
                incidentCount += ctx.DictionaryIncidents.Where(di => !di.Expunged && di.PerpetratorName == targetLower).LongCount();
            }

            if (_config.UsernamesToSpecialCountFormats.ContainsKey(targetLower))
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: {2}",
                                          salutation,
                                          message.UserName,
                                          string.Format(
                                              _config.UsernamesToSpecialCountFormats[targetLower],
                                              target,
                                              incidentCount
                                              )
                                          ));
            }
            else if (incidentCount == 0)
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: Subject [noparse]{2}[/noparse] may or may not have caused any incident.",
                                          salutation,
                                          message.UserName,
                                          target
                                          ));
            }
            else
            {
                Connector.SendMessage(string.Format(
                                          "{0} [noparse]{1}[/noparse]: Subject [noparse]{2}[/noparse] may or may not have caused {3} {4}.",
                                          salutation,
                                          message.UserName,
                                          target,
                                          incidentCount,
                                          incidentCount == 1 ? "incident" : "incidents"
                                          ));
            }
        }
예제 #22
0
        protected void PotentialReplayRequest(ChatboxMessage message)
        {
            var body  = message.BodyBBCode;
            var match = ReplayTrigger.Match(body);

            if (!match.Success)
            {
                return;
            }

            if (match.Groups[1].Length > 3)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: I am absolutely not replaying that many messages at once.",
                                          message.UserName
                                          ));
                return;
            }

            var replayCount = int.Parse(match.Groups[1].Value);

            if (replayCount > _config.MaxMessagesToReplay)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: I only remember a backlog of up to {1} messages.",
                                          message.UserName,
                                          _config.MaxMessagesToReplay
                                          ));
                return;
            }
            else if (replayCount == 0)
            {
                return;
            }

            var lowerSenderName = message.UserName.ToLowerInvariant();

            List <ReplayableMessage> messages;

            using (var ctx = GetNewContext())
            {
                // get the messages
                messages = ctx.ReplayableMessages
                           .Where(m => m.RecipientFolded == lowerSenderName)
                           .OrderByDescending(m => m.ID)
                           .Take(replayCount)
                           .ToList()
                ;
                messages.Reverse();
            }

            if (messages.Count == 0)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: You have no messages to replay!",
                                          message.UserName
                                          ));
                return;
            }
            if (messages.Count == 1)
            {
                Logger.DebugFormat("replaying a message for {0}", Util.LiteralString(message.UserName));
                Connector.SendMessage(string.Format(
                                          "Replaying message for [noparse]{0}[/noparse]! {1} <[noparse]{2}[/noparse]> {3}",
                                          message.UserName,
                                          FormatUtcTimestampFromDatabase(messages[0].ID, messages[0].Timestamp),
                                          messages[0].SenderOriginal,
                                          messages[0].Body
                                          ));
                return;
            }

            Connector.SendMessage(string.Format(
                                      "[noparse]{0}[/noparse]: Replaying {1} messages!",
                                      message.UserName,
                                      messages.Count
                                      ));
            Logger.DebugFormat(
                "replaying {0} messages for {1}",
                messages.Count,
                Util.LiteralString(message.UserName)
                );
            foreach (var msg in messages)
            {
                Connector.SendMessage(string.Format(
                                          "{0} <[noparse]{1}[/noparse]> {2}!",
                                          FormatUtcTimestampFromDatabase(msg.ID, msg.Timestamp),
                                          msg.SenderOriginal,
                                          msg.Body
                                          ));
            }
            Connector.SendMessage(string.Format(
                                      "[noparse]{0}[/noparse]: Take care!",
                                      message.UserName
                                      ));
        }
예제 #23
0
        /// <summary>
        /// Checks whether an existing ECHELON trigger is to be deleted or undeleted and potentially does so.
        /// </summary>
        protected void PotentialDeleteDictSpy(ChatboxMessage message)
        {
            var delDictMatch = DeleteSpyDictTrigger.Match(message.BodyBBCode);

            if (!delDictMatch.Success)
            {
                return;
            }

            var userLevel  = GetUserLevel(message.UserName);
            var salutation = userLevel.ToString();

            if (userLevel != UserLevel.Spymaster)
            {
                SendInsufficientRankMessage(salutation, message.UserName);
                return;
            }

            var undelete      = delDictMatch.Groups[1].Success;
            var dictTriggerID = long.Parse(delDictMatch.Groups[2].Value);

            using (var ctx = GetNewContext())
            {
                var dictTrig = ctx.DictionaryTriggers.FirstOrDefault(t => t.ID == dictTriggerID);
                if (dictTrig == null)
                {
                    Connector.SendMessage(string.Format(
                                              "{0} [noparse]{1}[/noparse]: The dictionary trigger with this ID does not exist.",
                                              salutation,
                                              message.UserName
                                              ));
                    return;
                }

                if (dictTrig.Deactivated && !undelete)
                {
                    Connector.SendMessage(string.Format(
                                              "{0} [noparse]{1}[/noparse]: The dictionary trigger with this ID is already deleted.",
                                              salutation,
                                              message.UserName
                                              ));
                    return;
                }
                else if (!dictTrig.Deactivated && undelete)
                {
                    Connector.SendMessage(string.Format(
                                              "{0} [noparse]{1}[/noparse]: The dictionary trigger with this ID is still active.",
                                              salutation,
                                              message.UserName
                                              ));
                    return;
                }

                dictTrig.Deactivated   = !undelete;
                dictTrig.SpymasterName = message.UserName;

                ctx.SaveChanges();
            }

            Connector.SendMessage(string.Format(
                                      "{0} [noparse]{1}[/noparse]: {2}.",
                                      salutation,
                                      message.UserName,
                                      undelete ? "Undeleted" : "Deleted"
                                      ));
        }
예제 #24
0
        protected void PotentialIgnoreListRequest(ChatboxMessage message)
        {
            var body  = message.BodyBBCode;
            var match = IgnoreTrigger.Match(body);

            if (!match.Success)
            {
                return;
            }

            var command             = match.Groups[1].Value;
            var blockSender         = match.Groups[2].Value.Trim();
            var blockSenderLower    = blockSender.ToLowerInvariant();
            var blockRecipientLower = message.UserName.ToLowerInvariant();

            bool isIgnored;

            using (var ctx = GetNewContext())
            {
                isIgnored = ctx.IgnoreList
                            .Any(ie => ie.SenderFolded == blockSenderLower && ie.RecipientFolded == blockRecipientLower);
            }

            if (command == "ignore")
            {
                if (isIgnored)
                {
                    Connector.SendMessage(string.Format(
                                              "[noparse]{0}[/noparse]: You are already ignoring [i][noparse]{1}[/noparse][/i].",
                                              message.UserName,
                                              blockSender
                                              ));
                    return;
                }

                using (var ctx = GetNewContext())
                {
                    var entry = new IgnoreEntry
                    {
                        SenderFolded    = blockSenderLower,
                        RecipientFolded = blockRecipientLower
                    };
                    ctx.IgnoreList.Add(entry);
                    ctx.SaveChanges();
                }
                Logger.DebugFormat(
                    "{0} is now ignoring {1}",
                    Util.LiteralString(message.UserName),
                    Util.LiteralString(blockSender)
                    );

                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: You are now ignoring [i][noparse]{1}[/noparse][/i].",
                                          message.UserName,
                                          blockSender
                                          ));
            }
            else if (command == "unignore")
            {
                if (!isIgnored)
                {
                    Connector.SendMessage(string.Format(
                                              "[noparse]{0}[/noparse]: You have not been ignoring [i][noparse]{1}[/noparse][/i].",
                                              message.UserName,
                                              blockSender
                                              ));
                    return;
                }

                using (var ctx = GetNewContext())
                {
                    var entry = ctx.IgnoreList
                                .FirstOrDefault(ie => ie.SenderFolded == blockSenderLower && ie.RecipientFolded == blockRecipientLower);
                    ctx.IgnoreList.Remove(entry);
                    ctx.SaveChanges();
                }
                Logger.DebugFormat(
                    "{0} is not ignoring {1} anymore",
                    Util.LiteralString(message.UserName),
                    Util.LiteralString(blockSender)
                    );

                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: You are not ignoring [i][noparse]{1}[/noparse][/i] anymore.",
                                          message.UserName,
                                          blockSender
                                          ));
            }
        }
예제 #25
0
        protected override void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false)
        {
            if (isBanned || isEdited || isPartOfInitialSalvo)
            {
                return;
            }

            if (message.UserName == Connector.ForumConfig.Username)
            {
                return;
            }

            var body        = message.BodyBBCode;
            var thanksMatch = ThankRegex.Match(body);

            if (thanksMatch.Success)
            {
                var nickname      = thanksMatch.Groups[1].Value.Trim();
                var lowerNickname = nickname.ToLowerInvariant();
                if (lowerNickname == message.UserName.ToLowerInvariant())
                {
                    Connector.SendMessage(string.Format(
                                              "You are so full of yourself, [noparse]{0}[/noparse].",
                                              message.UserName
                                              ));
                    return;
                }


                UserIDAndNickname?userInfo = null;
                try
                {
                    userInfo = Connector.UserIDAndNicknameForUncasedName(nickname);
                }
                catch (TransferException)
                {
                    // never mind
                }

                if (!userInfo.HasValue)
                {
                    Connector.SendMessage(string.Format(
                                              "I don't know '[noparse]{0}[/noparse]'!",
                                              nickname
                                              ));
                    return;
                }

                Logger.DebugFormat("{0} thanks {1}", message.UserName, nickname);

                long thankedCount = -1;
                using (var ctx = GetNewContext())
                {
                    var entry = ctx.ThanksEntries.Where(te => te.Thanker == message.UserName && te.ThankeeFolded == lowerNickname).FirstOrDefault();
                    if (entry == null)
                    {
                        entry = new ThanksEntry
                        {
                            Thanker       = message.UserName,
                            ThankeeFolded = lowerNickname,
                            ThankCount    = 1
                        };
                        ctx.ThanksEntries.Add(entry);
                    }
                    else
                    {
                        ++entry.ThankCount;
                    }
                    ctx.SaveChanges();

                    thankedCount = ctx.ThanksEntries.Where(te => te.ThankeeFolded == lowerNickname).Sum(te => te.ThankCount);
                }

                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: Alright! By the way, [noparse]{1}[/noparse] has been thanked {2} until now.",
                                          message.UserName,
                                          userInfo.Value.Nickname,
                                          (thankedCount == 1) ? "once" : (thankedCount + " times")
                                          ));
            }
            else if (body.StartsWith("!thanked "))
            {
                var nickname      = body.Substring(("!thanked ").Length).Trim();
                var lowerNickname = nickname.ToLowerInvariant();

                UserIDAndNickname?userInfo = null;
                try
                {
                    userInfo = Connector.UserIDAndNicknameForUncasedName(nickname);
                }
                catch (TransferException)
                {
                    // never mind
                }

                if (!userInfo.HasValue)
                {
                    Connector.SendMessage(string.Format(
                                              "I don't know '[noparse]{0}[/noparse]'!",
                                              nickname
                                              ));
                    return;
                }

                long thankedCount = -1;
                using (var ctx = GetNewContext())
                {
                    thankedCount = ctx.ThanksEntries.Where(te => te.ThankeeFolded == lowerNickname).Sum(te => te.ThankCount);
                }

                string countPhrase = null;
                bool   showStats   = (thankedCount != 0);

                if (thankedCount == 0)
                {
                    countPhrase = "not been thanked";
                }
                else if (thankedCount == 1)
                {
                    countPhrase = "been thanked once";
                }
                else
                {
                    countPhrase = string.Format("been thanked {0} times", thankedCount);
                }

                var statsString = "";
                if (showStats)
                {
                    List <string> mostGratefulStrings;
                    using (var ctx = GetNewContext())
                    {
                        mostGratefulStrings = ctx.ThanksEntries
                                              .Where(te => te.ThankeeFolded == lowerNickname)
                                              .OrderByDescending(te => te.ThankCount)
                                              .Take(_config.MostGratefulCount + 1)
                                              .ToList()
                                              .Select(te => string.Format("[noparse]{0}[/noparse]: {1}\u00D7", te.Thanker, te.ThankCount))
                                              .ToList();
                    }

                    // mention that the list is truncated if there are more than MostGratefulCount entries
                    var countString = (mostGratefulStrings.Count <= _config.MostGratefulCount) ? "" : (" " + _config.MostGratefulCountText);
                    statsString = string.Format(
                        " (Most grateful{0}: {1})",
                        countString,
                        string.Join(", ", mostGratefulStrings.Take(_config.MostGratefulCount))
                        );
                }

                Connector.SendMessage(string.Format(
                                          "[noparse]{0}: {1}[/noparse] has {2} until now.{3}",
                                          message.UserName,
                                          userInfo.Value.Nickname,
                                          countPhrase,
                                          statsString
                                          ));
            }
            else if (body == "!topthanked")
            {
                List <ThankeeAndCount> top;
                using (var ctx = GetNewContext())
                {
                    top = ctx.ThanksEntries
                          .GroupBy(te => te.ThankeeFolded)
                          .Select(teg => new ThankeeAndCount {
                        ThankeeFolded = teg.FirstOrDefault().ThankeeFolded,
                        ThankCount    = teg.Sum(te => te.ThankCount)
                    })
                          .OrderByDescending(teg => teg.ThankCount)
                          .Take(_config.MostThankedCount)
                          .ToList()
                    ;
                }

                var topStrings = new List <string>();
                foreach (var thankeeAndCount in top)
                {
                    var actualUsername = thankeeAndCount.ThankeeFolded;
                    try
                    {
                        var info = Connector.UserIDAndNicknameForUncasedName(thankeeAndCount.ThankeeFolded);
                        if (info.HasValue)
                        {
                            actualUsername = info.Value.Nickname;
                        }
                    }
                    catch (TransferException)
                    {
                    }
                    topStrings.Add(string.Format("{0}: {1}", actualUsername, thankeeAndCount.ThankCount));
                }

                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: {1}",
                                          message.UserName,
                                          string.Join(", ", topStrings)
                                          ));
            }
        }
예제 #26
0
        protected void PotentialMessageSend(ChatboxMessage message)
        {
            var body  = message.BodyBBCode;
            var match = MsgTrigger.Match(body);

            if (!match.Success)
            {
                return;
            }

            var lowerSenderName     = message.UserName.ToLowerInvariant();
            var recipientAndMessage = match.Groups[2].Value;
            RecipientAndMessage ram;

            try
            {
                ram = SplitRecipientAndMessage(recipientAndMessage);
            }
            catch (FormatException exc)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: {1}",
                                          message.UserName,
                                          exc.Message
                                          ));
                return;
            }

            var targetName      = Util.RemoveControlCharactersAndStrip(ram.Recipient);
            var lowerTargetName = targetName.ToLowerInvariant();
            var sendBody        = Util.RemoveControlCharactersAndStrip(ram.Message);

            //var lowerSenderName = message.UserName.ToLowerInvariant();

            if (lowerTargetName.Length == 0)
            {
                Connector.SendMessage(string.Format("[noparse]{0}[/noparse]: You must specify a name to deliver to!", message.UserName));
                return;
            }
            if (sendBody.Length == 0)
            {
                Connector.SendMessage(string.Format("[noparse]{0}[/noparse]: You must specify a message to deliver!", message.UserName));
                return;
            }
            if (lowerTargetName == Connector.ForumConfig.Username.ToLowerInvariant())
            {
                Connector.SendMessage(string.Format("[noparse]{0}[/noparse]: Sorry, I don\u2019t deliver to myself!", message.UserName));
                return;
            }

            UserIDAndNickname?userInfo;

            try
            {
                userInfo = Connector.UserIDAndNicknameForUncasedName(targetName);
            }
            catch (TransferException)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: Sorry, I couldn\u2019t verify if \u201c[noparse]{1}[/noparse] exists because the forum isn\u2019t being cooperative. Please try again later!",
                                          message.UserName, targetName
                                          ));
                return;
            }

            if (!userInfo.HasValue)
            {
                var colonInfo = "";
                if (sendBody.Contains(":"))
                {
                    colonInfo = " (You may escape colons in usernames using a backslash.)";
                }
                else if (targetName.Length > 32)
                {
                    colonInfo = " (You must place a colon between the username and the message.)";
                }
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: Sorry, I don\u2019t know \u201c[noparse]{1}[/noparse]\u201d.{2}",
                                          message.UserName, targetName, colonInfo
                                          ));
                return;
            }

            // check ignore list
            bool isIgnored;

            using (var ctx = GetNewContext())
            {
                isIgnored = ctx.IgnoreList.Any(il => il.SenderFolded == lowerSenderName && il.RecipientFolded == lowerTargetName);
            }

            if (isIgnored)
            {
                Logger.DebugFormat(
                    "{0} wants to send message {1} to {2}, but the recipient is ignoring the sender",
                    Util.LiteralString(message.UserName),
                    Util.LiteralString(sendBody),
                    Util.LiteralString(targetName)
                    );
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: Can\u2019t send a message to [i][noparse]{1}[/noparse][/i]\u2014they\u2019re ignoring you.",
                                          message.UserName,
                                          userInfo.Value.Nickname
                                          ));
                return;
            }

            Logger.DebugFormat(
                "{0} sending message {1} to {2}",
                Util.LiteralString(message.UserName),
                Util.LiteralString(sendBody),
                Util.LiteralString(targetName)
                );

            using (var ctx = GetNewContext())
            {
                var msg = new Message
                {
                    ID              = message.ID,
                    Timestamp       = message.Timestamp.ToUniversalTimeForDatabase(),
                    SenderOriginal  = message.UserName,
                    RecipientFolded = lowerTargetName,
                    Body            = sendBody
                };
                ctx.Messages.Add(msg);
                ctx.SaveChanges();
            }

            if (match.Groups[1].Value == "s")
            {
                // silent msg
                return;
            }

            if (lowerTargetName == lowerSenderName)
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: Talking to ourselves? Well, no skin off my back. I\u2019ll deliver your message to you right away. ;)",
                                          message.UserName
                                          ));
            }
            else
            {
                Connector.SendMessage(string.Format(
                                          "[noparse]{0}[/noparse]: Aye-aye! I\u2019ll deliver your message to [i][noparse]{1}[/noparse][/i] next time I see \u2019em!",
                                          message.UserName,
                                          userInfo.Value.Nickname
                                          ));
            }
        }
예제 #27
0
        /// <summary>
        /// Checks whether an existing ECHELON trigger is to be modified and potentially does so.
        /// </summary>
        protected void PotentialModifySpy(ChatboxMessage message)
        {
            var modMatch    = ModifySpyTrigger.Match(message.BodyBBCode);
            var modMatchAll = ModifySpyAllTrigger.Match(message.BodyBBCode);

            long   triggerID;
            string triggerUsernameLower;
            string triggerRegex;

            if (modMatch.Success)
            {
                triggerID            = long.Parse(modMatch.Groups[1].Value);
                triggerUsernameLower = modMatch.Groups[2].Value.Trim().ToLowerInvariant();
                triggerRegex         = modMatch.Groups[3].Value.Trim();
            }
            else if (modMatchAll.Success)
            {
                triggerID            = long.Parse(modMatchAll.Groups[1].Value);
                triggerUsernameLower = null;
                triggerRegex         = modMatchAll.Groups[2].Value.Trim();
            }
            else
            {
                return;
            }

            var userLevel  = GetUserLevel(message.UserName);
            var salutation = userLevel.ToString();

            if (userLevel != UserLevel.Spymaster)
            {
                SendInsufficientRankMessage(salutation, message.UserName);
                return;
            }

            using (var ctx = GetNewContext())
            {
                var trig = ctx.Triggers.FirstOrDefault(t => t.Id == triggerID);
                if (trig == null)
                {
                    Connector.SendMessage(string.Format(
                                              "{0} [noparse]{1}[/noparse]: The trigger with this ID does not exist.",
                                              salutation,
                                              message.UserName
                                              ));
                    return;
                }

                trig.TargetNameLower = triggerUsernameLower;
                trig.Regex           = triggerRegex;
                trig.SpymasterName   = message.UserName;

                ctx.SaveChanges();
            }

            Connector.SendMessage(string.Format(
                                      "{0} [noparse]{1}[/noparse]: Updated.",
                                      salutation,
                                      message.UserName
                                      ));
        }