/* 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(); } } } }