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", "Threeplicate S.r.l.", "3.0.0.206", "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 = @"";
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; }
}
}
}