using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using System.Xml; using ScrewTurn.Wiki.PluginFramework; using System.Net; using System.IO; namespace ScrewTurn.Wiki.Plugins.PluginPack { /// /// Implements a formatter provider that counts download of files and attachments. /// public class RssFeedDisplay : IFormatterProviderV30 { private IHostV30 _host; private string _config; private bool _enableLogging = true; private static readonly ComponentInformation Info = new ComponentInformation("RSS Feed Display Plugin", "ScrewTurn Software", "3.0.1.453", "http://www.screwturn.eu", "http://www.screwturn.eu/Version/PluginPack/RssFeedDisplay.txt"); private static readonly Regex RssRegex = new Regex(@"{RSS:http://(.+?)}", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); /// /// Specifies whether or not to execute Phase 1. /// public bool PerformPhase1 { get { return false; } } /// /// Specifies whether or not to execute Phase 2. /// public bool PerformPhase2 { get { return false; } } /// /// Specifies whether or not to execute Phase 3. /// public bool PerformPhase3 { get { return true; } } /// /// Gets the execution priority of the provider (0 lowest, 100 highest). /// public int ExecutionPriority { get { return 50; } } /// /// Performs a Formatting phase. /// /// The raw content to Format. /// The Context information. /// The Phase. /// The Formatted content. public string Format(string raw, ContextInformation context, FormattingPhase phase) { // {RSS:FeedAddress} // FeedAddress not found -> ignored StringBuilder buffer = new StringBuilder(raw); try { KeyValuePair block = FindAndRemoveFirstOccurrence(buffer); while(block.Key != -1) { string blockHash = block.Value.ToString(); string result = null; if(System.Web.HttpContext.Current != null) { result = System.Web.HttpContext.Current.Cache[blockHash] as string; } if(result == null) { XmlDocument feedXml = GetXml(block.Value.ToString().Substring(5, block.Value.ToString().Length - 6)); XmlNode node = feedXml.DocumentElement; XmlNode itemTitle = node.SelectNodes("/rss/channel/item/title")[0]; XmlNode itemLink = node.SelectNodes("/rss/channel/item/link")[0]; XmlNode itemContent = node.SelectNodes("/rss/channel/item/description")[0]; String itemContentStr = StripHtml(itemContent.InnerText); itemContentStr = (itemContentStr.Length > 350 && itemContentStr.Substring(347, 5) != "[...]") ? itemContentStr.Substring(0, itemContentStr.IndexOf(" ", 345)) + " [...]" : itemContentStr; result = @"
" + itemTitle.InnerText + @"
" + itemContentStr + @"
"; if(System.Web.HttpContext.Current != null) { System.Web.HttpContext.Current.Cache.Add(blockHash, result, null, DateTime.Now.AddMinutes(60), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null); } } buffer.Insert(block.Key, result); block = FindAndRemoveFirstOccurrence(buffer); } } catch(Exception ex) { LogWarning(string.Format("Exception occurred: {0}", ex.Message)); return null; } return buffer.ToString(); } /// /// Produces an API call, then returns the results as an Xml Document /// /// The Url to the specific API call /// private XmlDocument GetXml(string Url) { try { var results = new XmlDocument(); Url = string.Format("{0}", Url); var request = WebRequest.Create(Url); var response = request.GetResponse(); using(var reader = new StreamReader(response.GetResponseStream())) { var xmlString = reader.ReadToEnd(); try { results.LoadXml(xmlString); } catch { LogWarning("Received Unexpected Response from Unfuddle Server."); } } return results; } catch(Exception ex) { LogWarning(string.Format("Exception occurred: {0}", ex.Message)); return null; } } /// /// Finds and removes the first occurrence of the custom tag. /// /// The buffer. /// The index->content data. private static KeyValuePair FindAndRemoveFirstOccurrence(StringBuilder buffer) { Match match = RssRegex.Match(buffer.ToString()); if(match.Success) { buffer.Remove(match.Index, match.Length); return new KeyValuePair(match.Index, match.Value); } return new KeyValuePair(-1, null); } /// /// Removes all HTML markup from a string. /// /// The string. /// The result. private static string StripHtml(string content) { if(string.IsNullOrEmpty(content)) return ""; StringBuilder sb = new StringBuilder(Regex.Replace(content, "<[^>]*>", " ")); sb.Replace(" ", ""); sb.Replace(" ", " "); return sb.ToString(); } /// /// Prepares the title of an item for display (always during phase 3). /// /// The input title. /// The context information. /// The prepared title (no markup allowed). public string PrepareTitle(string title, ContextInformation context) { return title; } /// /// Initializes the Storage Provider. /// /// The Host of the Component. /// The Configuration data, if any. /// If the configuration string is not valid, the methoud should throw a . public void Init(IHostV30 host, string config) { this._host = host; this._config = config != null ? config : ""; if(this._config.ToLowerInvariant() == "nolog") _enableLogging = false; } /// /// Logs a warning. /// /// The message. private void LogWarning(string message) { if(_enableLogging) { _host.LogEntry(message, LogEntryType.Warning, null, this); } } /// /// Method invoked on shutdown. /// /// This method might not be invoked in some cases. public void Shutdown() { // Nothing to do } /// /// Gets the Information about the Provider. /// public ComponentInformation Information { get { return Info; } } /// /// Gets a brief summary of the configuration string format, in HTML. Returns null if no configuration is needed. /// public string ConfigHelpHtml { get { return null; } } } }