/* RssFeed.cs
* ==========
*
* RSS.NET (http://rss-net.sf.net/)
* Copyright © 2002, 2003 George Tsiokos. All Rights Reserved.
*
* RSS 2.0 (http://blogs.law.harvard.edu/tech/rss)
* RSS 2.0 is offered by the Berkman Center for Internet & Society at
* Harvard Law School under the terms of the Attribution/Share Alike
* Creative Commons license.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Net;
using System.Text;
namespace Rss
{
/// The contents of a RssFeed
[Serializable()]
public class RssFeed
{
private RssChannelCollection channels = new RssChannelCollection();
private RssModuleCollection modules = new RssModuleCollection();
private ExceptionCollection exceptions = null;
private DateTime lastModified = RssDefault.DateTime;
private RssVersion rssVersion = RssVersion.Empty;
private bool cached = false;
private string etag = RssDefault.String;
private string url = RssDefault.String;
private Encoding encoding = null;
/// Initialize a new instance of the RssFeed class.
public RssFeed() {}
/// Initialize a new instance of the RssFeed class with a specified encoding.
public RssFeed(Encoding encoding)
{
this.encoding = encoding;
}
/// Returns a string representation of the current Object.
/// The Url of the feed
public override string ToString()
{
return url;
}
/// The channels that are contained in the feed.
public RssChannelCollection Channels
{
get { return channels; }
}
/// The modules that the feed adhears to.
public RssModuleCollection Modules
{
get { return modules; }
}
/// A collection of all exceptions encountered during the reading of the feed.
public ExceptionCollection Exceptions
{
get { return exceptions == null ? new ExceptionCollection() : exceptions; }
}
/// The Version of the feed.
public RssVersion Version
{
get { return rssVersion; }
set { rssVersion = value; }
}
/// The server generated hash of the feed.
public string ETag
{
get { return etag; }
}
/// The server generated last modfified date and time of the feed.
public DateTime LastModified
{
get { return lastModified; }
}
/// Indicates this feed has not been changed on the server, and the local copy was returned.
public bool Cached
{
get { return cached; }
}
/// Location of the feed
public string Url
{
get { return url; }
}
/// Encoding of the feed
public Encoding Encoding
{
get { return encoding; }
set { encoding = value; }
}
/// Reads the specified RSS feed
/// The url or filename of the RSS feed
/// The contents of the feed
public static RssFeed Read(string url)
{
return read(url, null, null);
}
/// Reads the specified RSS feed
/// The specified way to connect to the web server
/// The contents of the feed
public static RssFeed Read(HttpWebRequest Request)
{
return read(Request.RequestUri.ToString(), Request, null);
}
/// Reads the specified RSS feed
/// The cached version of the feed
/// The current contents of the feed
/// Will not download the feed if it has not been modified
public static RssFeed Read(RssFeed oldFeed)
{
return read(oldFeed.url, null, oldFeed);
}
/// Reads the specified RSS feed
/// The specified way to connect to the web server
/// The cached version of the feed
/// The current contents of the feed
/// Will not download the feed if it has not been modified
public static RssFeed Read(HttpWebRequest Request, RssFeed oldFeed)
{
return read(oldFeed.url, Request, oldFeed);
}
private static RssFeed read(string url, HttpWebRequest request, RssFeed oldFeed)
{
// ***** Marked for substantial improvement
RssFeed feed = new RssFeed();
RssElement element = null;
Stream stream = null;
Uri uri = new Uri(url);
feed.url = url;
switch (uri.Scheme)
{
case "file":
feed.lastModified = File.GetLastWriteTime(url);
if ((oldFeed != null) && (feed.LastModified == oldFeed.LastModified))
{
oldFeed.cached = true;
return oldFeed;
}
stream = new FileStream(url, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
break;
case "https":
goto case "http";
case "http":
if (request == null)
request = (HttpWebRequest)WebRequest.Create(uri);
if (oldFeed != null)
{
request.IfModifiedSince = oldFeed.LastModified;
request.Headers.Add("If-None-Match", oldFeed.ETag);
}
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
feed.lastModified = response.LastModified;
feed.etag = response.Headers["ETag"];
try
{
if (response.ContentEncoding != "")
feed.encoding = Encoding.GetEncoding(response.ContentEncoding);
}
catch {}
stream = response.GetResponseStream();
}
catch (WebException we)
{
if (oldFeed != null)
{
oldFeed.cached = true;
return oldFeed;
}
else throw we; // bad
}
break;
}
if (stream != null)
{
RssReader reader = null;
try
{
reader = new RssReader(stream);
do
{
element = reader.Read();
if (element is RssChannel)
feed.Channels.Add((RssChannel)element);
}
while (element != null);
feed.rssVersion = reader.Version;
}
finally
{
feed.exceptions = reader.Exceptions;
reader.Close();
}
}
else
throw new ApplicationException("Not a valid Url");
return feed;
}
/// Writes the RSS feed to the specified stream.
/// specified Stream
/// The Stream cannot be written to.
/// Feed must contain at least one channel.
/// Channel must contain at least one item.
public void Write(Stream stream)
{
RssWriter writer;
if (encoding == null)
writer = new RssWriter(stream);
else
writer = new RssWriter(stream, encoding);
write(writer);
}
/// Writes the RSS feed to the specified file.
/// The encoding is ISO-8859-1.
/// The filename is empty, contains only white space, or contains one or more invalid characters.
/// Access is denied.
/// The filename is a (null c#, Nothing vb) reference.
/// The directory to write to is not found.
/// The filename includes an incorrect or invalid syntax for file name, directory name, or volume label syntax.
/// The caller does not have the required permission.
/// specified file (including path) If the file exists, it will be truncated with the new content.
/// Feed must contain at least one channel.
/// Channel must contain at least one item.
public void Write(string fileName)
{
RssWriter writer = new RssWriter(fileName);
write(writer);
}
private void write(RssWriter writer)
{
try
{
if (channels.Count == 0)
throw new InvalidOperationException("Feed must contain at least one channel.");
writer.Version = rssVersion;
writer.Modules = modules;
foreach(RssChannel channel in channels)
{
if (channel.Items.Count == 0)
throw new InvalidOperationException("Channel must contain at least one item.");
writer.Write(channel);
}
}
finally
{
if (writer != null)
writer.Close();
}
}
}
}