protected abstract void ProcessUpdatedMessage(ChatboxMessage message, bool isPartOfInitialSalvo = false, bool isEdited = false, bool isBanned = false);
/// <summary> /// Fetches new messages from the chatbox. /// </summary> /// <param name="retry">Level of desperation fetching the new messages.</param> protected void FetchNewMessages(int retry = 0) { string messagesResponse; try { messagesResponse = WebGetPage(MessagesUrl); } catch (WebException ex) { Logger.WarnFormat("fetching new messages failed, retry {0}\n{1}", retry, ex); // try harder Retry(retry, () => FetchNewMessages(retry + 1)); return; } var messages = new HtmlDocument(); messages.LoadHtml(messagesResponse); if (messages.DocumentNode == null) { // dang Retry(retry, () => FetchNewMessages(retry + 1)); return; } var allTrs = messages.DocumentNode.SelectNodesOrEmpty("/tr"); if (allTrs.Count == 0) { // aw crap Retry(retry, () => FetchNewMessages(retry + 1)); return; } var newLastMessage = _lastMessageReceived; var visibleMessageIDs = new HashSet <long>(); var newAndEditedMessages = new Stack <MessageToDistribute>(); // for each message foreach (var tr in allTrs) { // pick out the TDs var tds = tr.SelectNodesOrEmpty("./td"); if (tds.Count != 2) { continue; } // pick out the first (metadata) var metaTd = tds[0]; var bodyTd = tds[1]; // find the link to the message and to the user var messageID = FishOutID(metaTd, MessageIDPiece); var userID = FishOutID(metaTd, UserIDPiece); if (!messageID.HasValue || !userID.HasValue) { // bah, humbug continue; } if (newLastMessage < messageID.Value) { newLastMessage = messageID.Value; } visibleMessageIDs.Add(messageID.Value); // fetch the timestamp var timestamp = DateTime.Now; var timestampMatch = TimestampPattern.Match(metaTd.InnerHtml); if (timestampMatch.Success) { var timeString = timestampMatch.Groups[1].Value; DateTime parsed; if (DateTime.TryParseExact( timeString, "dd-MM-yy, HH:mm", CultureInfo.InvariantCulture, ForumConfig.UtcTime ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal, out parsed )) { timestamp = parsed; } } // get the nickname HtmlNode nickElement = null; foreach (var linkElement in metaTd.SelectNodesOrEmpty(".//a[@href]")) { if (linkElement.GetAttributeValue("href", null).Contains(UserIDPiece)) { nickElement = linkElement; } } if (nickElement == null) { // bah, humbug continue; } var nick = nickElement.InnerText; var isBanned = ForumConfig.LowercaseBannedUsers.Contains(nick.ToLowerInvariant()); // cache the nickname _lowercaseUsernamesToUserIDNamePairs[nick.ToLowerInvariant()] = new UserIDAndNickname(userID.Value, nick); var message = new ChatboxMessage( messageID.Value, userID.Value, nickElement, bodyTd, timestamp, Decompiler ); var body = bodyTd.InnerHtml; if (_oldMessageIDsToBodies.ContainsKey(messageID.Value)) { var oldBody = _oldMessageIDsToBodies[messageID.Value]; if (oldBody != body) { _oldMessageIDsToBodies[messageID.Value] = body; newAndEditedMessages.Push(new MessageToDistribute(_initialSalvo, true, isBanned, message)); } } else { _oldMessageIDsToBodies[messageID.Value] = body; newAndEditedMessages.Push(new MessageToDistribute(_initialSalvo, false, isBanned, message)); } } // port the bodies of messages that are still visible var messageIDsToBodies = new Dictionary <long, string>(); foreach (var pair in _oldMessageIDsToBodies) { if (visibleMessageIDs.Contains(pair.Key)) { messageIDsToBodies[pair.Key] = pair.Value; } } _oldMessageIDsToBodies = messageIDsToBodies; // distribute the news and modifications while (newAndEditedMessages.Count > 0) { var msg = newAndEditedMessages.Pop(); OnMessageUpdated(new MessageUpdatedEventArgs { Message = msg }); } _initialSalvo = false; _lastMessageReceived = newLastMessage; }