using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Net; using System.Xml; using System.Reflection; namespace RSSViewer { public partial class frmMain : Form { string[] arrMonths = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; private int strContainsMonth( string s ) { int c = 12; for ( int i = 0; i < c; i++ ) { if ( s.Contains( arrMonths[i] ) ) { return i; } } return -1; } const int C_SCREEN_FEEDS = 0; const int C_SCREEN_ENTRIES = 1; const int C_SCREEN_SHOWENTRY = 2; const int C_SCREEN_ADDFEED = 3; private int iCurrentScreen = C_SCREEN_FEEDS; private int iFeedIndex = -1; private int iEntryIndex = -1; private int iXmlType = -1; private XmlDocument settingsXMLDocument = null; private XmlDocument feedXMLDocument = null; private XmlNode feedNode = null; private string sCurrentFeedUrl = ""; private string sCurrentFeedShortname = ""; private string C_TAG_MAIN = ""; private string C_TAG_ENTRY = ""; private string C_TAG_TITLE = ""; private string C_TAG_CONTENT = ""; private string C_TAG_DATE = ""; private string C_TAG_CONTENT_FALLBACK = ""; const int C_XMLTYPE_ATOM = 0; const int C_XMLTYPE_RSS = 1; private string sSettingsXmlFilename = ""; private bool bReadOffline = false; public void setXmlType( int i ) { switch ( i ) { case C_XMLTYPE_ATOM: C_TAG_MAIN = "feed"; C_TAG_ENTRY = "entry"; C_TAG_TITLE = "title"; C_TAG_DATE = "updated"; C_TAG_CONTENT = "content"; C_TAG_CONTENT_FALLBACK = "content"; break; case C_XMLTYPE_RSS: C_TAG_MAIN = "channel"; C_TAG_ENTRY = "item"; C_TAG_TITLE = "title"; C_TAG_DATE = "pubDate"; C_TAG_CONTENT = "content:encoded"; C_TAG_CONTENT_FALLBACK = "description"; break; } } private string sCurrentDirectory = ""; private void loadCurrentDirectory() { sCurrentDirectory = ""; try { sCurrentDirectory = Path.GetDirectoryName( Assembly.GetExecutingAssembly().GetName().CodeBase ); if ( !sCurrentDirectory.EndsWith( "\\" ) ) { sCurrentDirectory += "\\"; } } catch ( Exception ) { sCurrentDirectory = ""; } } public frmMain() { InitializeComponent(); loadCurrentDirectory(); lstFeeds.Visible = false; lstEntries.Visible = false; edtEntryText.Visible = false; webEntryText.Visible = false; lstFeeds.Dock = DockStyle.Fill; lstEntries.Dock = DockStyle.Fill; edtEntryText.Dock = DockStyle.Fill; webEntryText.Dock = DockStyle.Fill; lstFeeds.View = View.Details; lstFeeds.FullRowSelect = true; lstFeeds.HeaderStyle = ColumnHeaderStyle.Clickable; lstFeeds.Columns.Add( "Channel", 220, HorizontalAlignment.Left ); lstEntries.View = View.Details; lstEntries.FullRowSelect = true; lstEntries.HeaderStyle = ColumnHeaderStyle.Clickable; lstEntries.Columns.Add( "Date", 100, HorizontalAlignment.Left ); lstEntries.Columns.Add( "Title", 200, HorizontalAlignment.Left ); edtEntryText.ScrollBars = ScrollBars.Vertical; sSettingsXmlFilename = sCurrentDirectory + "RSSViewer.xml"; settingsXMLDocument = new XmlDocument(); try { settingsXMLDocument.LoadXml( readFromFile( sSettingsXmlFilename ) ); } catch ( Exception ) { XmlElement node = settingsXMLDocument.CreateElement( "feeds" ); settingsXMLDocument.AppendChild( node ); saveAsFile( sSettingsXmlFilename, settingsXMLDocument.OuterXml ); } showFeeds(); lstFeeds.Visible = true; bReadOffline = false; miReadOffline.Checked = bReadOffline; } private void addFeed( string shortname, string longname, string url, int xmltype ) { XmlNode feedsNode = getChildNodeByName( settingsXMLDocument, "feeds" ); XmlElement feed = settingsXMLDocument.CreateElement( "feed" ); XmlAttribute attrib; attrib = settingsXMLDocument.CreateAttribute( "shortname" ); attrib.Value = shortname; feed.Attributes.Append( attrib ); attrib = settingsXMLDocument.CreateAttribute( "longname" ); attrib.Value = longname; feed.Attributes.Append( attrib ); attrib = settingsXMLDocument.CreateAttribute( "url" ); attrib.Value = url; feed.Attributes.Append( attrib ); attrib = settingsXMLDocument.CreateAttribute( "xmltype" ); attrib.Value = xmltype.ToString(); feed.Attributes.Append( attrib ); feedsNode.AppendChild( feed ); saveAsFile( sSettingsXmlFilename, settingsXMLDocument.OuterXml ); } private void showFeeds() { lstFeeds.Items.Clear(); XmlNode feedsNode = getChildNodeByName( settingsXMLDocument, "feeds" ); int c = feedsNode.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode node = feedsNode.ChildNodes[i]; if ( node.Name.Equals( "feed" ) ) { XmlNode shortname = node.Attributes.GetNamedItem( "shortname" ); XmlNode longname = node.Attributes.GetNamedItem( "longname" ); XmlNode url = node.Attributes.GetNamedItem( "url" ); ListViewItem item = new ListViewItem( longname.Value ); lstFeeds.Items.Add( item ); } } lstFeeds.Focus(); } private XmlNode getFeedNode( int index ) { XmlNode feedsNode = getChildNodeByName( settingsXMLDocument, "feeds" ); int iCurrentNode = 0; int c = feedsNode.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode node = feedsNode.ChildNodes[i]; if ( node.Name.Equals( "feed" ) ) { if ( index == iCurrentNode ) { return node; } iCurrentNode++; } } return null; } private string downloadFile( string url ) { HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create( url ); loHttp.Timeout = 10000; // 10 secs loHttp.UserAgent = "RSSViewer"; HttpWebResponse loWebResponse = (HttpWebResponse)loHttp.GetResponse(); Encoding enc = Encoding.GetEncoding( 65001 ); // UTF8? StreamReader loResponseStream = new StreamReader( loWebResponse.GetResponseStream(), enc ); string lcHtml = loResponseStream.ReadToEnd(); loWebResponse.Close(); loResponseStream.Close(); return lcHtml; } private void saveAsFile( string filename, string contents ) { StreamWriter sw = File.CreateText( filename ); sw.Write( contents ); sw.Close(); } private string readFromFile( string filename ) { string contents = ""; try { StreamReader sr = File.OpenText( filename ); contents = sr.ReadToEnd(); sr.Close(); } catch ( Exception ) { } return contents; } private string downloadFeed( string url, string localfile ) { string contents = ""; contents = downloadFile( url ); saveAsFile( localfile, contents ); return contents; } private void showEntries() { int c = feedNode.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode entryNode = feedNode.ChildNodes[i]; if ( entryNode.Name.Equals( C_TAG_ENTRY ) ) { XmlNode updatedNode = getChildNodeByName( entryNode, C_TAG_DATE ); DateTime dt; string datestr = updatedNode.InnerText; if ( iXmlType == C_XMLTYPE_ATOM ) { dt = XmlConvert.ToDateTime( datestr, XmlDateTimeSerializationMode.RoundtripKind ); datestr = dt.ToShortDateString() + " - " + dt.ToShortTimeString(); } else { try { // "Mon, 07 Jul 2008 22:02:05 +0000" datestr = datestr.Substring( datestr.IndexOf( ", " ) + 2 ); int p = datestr.LastIndexOf( " " ); if ( p != -1 ) { datestr = datestr.Substring( 0, p ); } int m = strContainsMonth( datestr ); if ( m != -1 ) { datestr = datestr.Replace( " " + arrMonths[m] + " ", "-" + (m + 1) + "-" ); } dt = XmlConvert.ToDateTime( datestr, "d-M-yyyy HH:mm:ss" ); datestr = dt.ToShortDateString() + " - " + dt.ToShortTimeString(); } catch ( Exception ) { //datestr = updatedNode.InnerText; } } string title = "untitled"; XmlNode titleNode = getChildNodeByName( entryNode, C_TAG_TITLE ); if ( titleNode != null ) { title = titleNode.InnerText; } ListViewItem item = new ListViewItem( datestr ); item.SubItems.Add( title ); lstEntries.Items.Add( item ); } } } private XmlNode getEntryNode( int index ) { int iCurrentNode = 0; int c = feedNode.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode entryNode = feedNode.ChildNodes[i]; if ( entryNode.Name.Equals( C_TAG_ENTRY ) ) { if ( index == iCurrentNode ) { return entryNode; } iCurrentNode++; } } return null; } private XmlNode getChildNodeByName( XmlNode parent, string name ) { int c = parent.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode node = parent.ChildNodes[i]; if ( node.Name.Equals( name ) ) { return node; } } return null; } private XmlNode digAndFindNodeByName( XmlNode parent, string name ) { int c = parent.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode node = parent.ChildNodes[i]; if ( node.Name.Equals( name ) ) { return node; } else { node = digAndFindNodeByName( node, name ); if ( node != null ) { return node; } } } return null; } private void refreshEntryList() { string sCurrentFeedLocalfile = sCurrentDirectory + sCurrentFeedShortname + ".xml"; lstEntries.Items.Clear(); try { string contents = ""; try { // try online if ( !bReadOffline ) { contents = downloadFeed( sCurrentFeedUrl, sCurrentFeedLocalfile ); this.Text = "RSSViewer - Online"; } else { contents = readFromFile( sCurrentFeedLocalfile ); this.Text = "RSSViewer - Offline"; } } catch ( Exception ) { // try offline contents = readFromFile( sCurrentFeedLocalfile ); this.Text = "RSSViewer - Offline"; } if ( contents.Length != 0 ) { feedXMLDocument = new XmlDocument(); try { feedXMLDocument.LoadXml( contents ); feedNode = digAndFindNodeByName( feedXMLDocument, C_TAG_MAIN ); showEntries(); } catch ( Exception ) { throw new Exception( "Invalid feed data" ); } } else { throw new Exception("Feed is empty"); } } catch ( Exception e ) { MessageBox.Show( e.Message ); } lstEntries.Focus(); } private void enablePopupMenu() { miButton1.MenuItems.Clear(); miButton1.MenuItems.Add( miDownloadAll ); miButton1.MenuItems.Add( miAddFeed ); miButton1.MenuItems.Add( miRemoveFeed ); miButton1.MenuItems.Add( miReadOffline ); } private void disablePopupMenu() { miButton1.MenuItems.Clear(); } private void miButton1_Click( object sender, EventArgs e ) { Cursor.Current = Cursors.WaitCursor; switch ( iCurrentScreen ) { case C_SCREEN_FEEDS: break; case C_SCREEN_ENTRIES: lstEntries.Visible = false; lstFeeds.Visible = true; iCurrentScreen = C_SCREEN_FEEDS; miButton1.Text = "Menu"; miButton2.Text = "View"; this.Text = "RSSViewer"; enablePopupMenu(); lstFeeds.Focus(); break; case C_SCREEN_SHOWENTRY: edtEntryText.Visible = false; webEntryText.Visible = false; lstEntries.Visible = true; iCurrentScreen = C_SCREEN_ENTRIES; miButton1.Text = "Back"; miButton2.Text = "View"; miButton2.Enabled = true; this.Text = "RSSViewer"; disablePopupMenu(); lstEntries.Focus(); break; } Cursor.Current = Cursors.Default; } private void miViewFeed_Click( object sender, EventArgs e ) { Cursor.Current = Cursors.WaitCursor; switch ( iCurrentScreen ) { case C_SCREEN_FEEDS: if ( lstFeeds.SelectedIndices.Count > 0 ) { iFeedIndex = lstFeeds.SelectedIndices[0]; lstFeeds.Visible = false; lstEntries.Visible = true; miButton1.Text = "Back"; miButton2.Text = "View"; iCurrentScreen = C_SCREEN_ENTRIES; disablePopupMenu(); XmlNode node = getFeedNode( iFeedIndex ); XmlNode shortname = node.Attributes.GetNamedItem( "shortname" ); XmlNode url = node.Attributes.GetNamedItem( "url" ); XmlNode xmltype = node.Attributes.GetNamedItem( "xmltype" ); iXmlType = int.Parse( xmltype.Value ); setXmlType( iXmlType ); sCurrentFeedShortname = shortname.Value; sCurrentFeedUrl = url.Value; refreshEntryList(); } break; case C_SCREEN_ENTRIES: if ( lstEntries.SelectedIndices.Count > 0 ) { iEntryIndex = lstEntries.SelectedIndices[0]; lstEntries.Visible = false; //edtEntryText.Visible = true; webEntryText.Visible = true; miButton1.Text = "Back"; miButton2.Text = ""; miButton2.Enabled = false; iCurrentScreen = C_SCREEN_SHOWENTRY; disablePopupMenu(); XmlNode node = getEntryNode( iEntryIndex ); XmlNode title = getChildNodeByName( node, C_TAG_TITLE ); XmlNode content = getChildNodeByName( node, C_TAG_CONTENT ); if ( content == null ) { content = getChildNodeByName( node, C_TAG_CONTENT_FALLBACK ); } if ( title != null ) { this.Text = title.InnerText; } else { this.Text = "Untitled entry"; } edtEntryText.Text = content.InnerText; webEntryText.DocumentText = content.InnerText; } break; default: break; } Cursor.Current = Cursors.Default; } private void miAddFeed_Click( object sender, EventArgs e ) { Cursor.Current = Cursors.Default; try { frmAddFeed addFeedForm = new frmAddFeed(); DialogResult iResult = addFeedForm.ShowDialog(); Cursor.Current = Cursors.WaitCursor; if ( iResult == DialogResult.OK ) { addFeed( addFeedForm.getShortName(), addFeedForm.getLongName(), addFeedForm.getUrl(), addFeedForm.getXmlType() ); showFeeds(); } lstFeeds.Focus(); } catch ( Exception exc ) { MessageBox.Show( exc.Message ); } Cursor.Current = Cursors.Default; } private void miDownloadAll_Click( object sender, EventArgs e ) { Cursor.Current = Cursors.WaitCursor; try { XmlNode feedsNode = getChildNodeByName( settingsXMLDocument, "feeds" ); int c = feedsNode.ChildNodes.Count; for ( int i = 0; i < c; i++ ) { XmlNode node = feedsNode.ChildNodes[i]; if ( node.Name.Equals( "feed" ) ) { XmlNode shortname = node.Attributes.GetNamedItem( "shortname" ); XmlNode url = node.Attributes.GetNamedItem( "url" ); downloadFeed( url.InnerText, sCurrentDirectory + shortname.InnerText + ".xml" ); } } } catch ( Exception exc ) { MessageBox.Show( exc.Message ); } Cursor.Current = Cursors.Default; } private void deleteFeed( int i ) { XmlNode node = getFeedNode( i ); XmlNode shortname = node.Attributes.GetNamedItem( "shortname" ); try { if ( File.Exists( sCurrentDirectory + shortname.Value + ".xml" ) ) { File.Delete( sCurrentDirectory + shortname.Value + ".xml" ); } } catch ( Exception ) { } node.ParentNode.RemoveChild( node ); saveAsFile( sSettingsXmlFilename, settingsXMLDocument.OuterXml ); } private void miRemoveFeed_Click( object sender, EventArgs e ) { if ( lstFeeds.SelectedIndices.Count > 0 ) { int i = lstFeeds.SelectedIndices[0]; XmlNode node = getFeedNode( i ); if ( MessageBox.Show( "Are you sure you want to remove this feed: '" + node.Attributes.GetNamedItem( "longname" ).Value + "'", "Remove feed", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2 ) == DialogResult.Yes ) { deleteFeed( i ); showFeeds(); } } } private void miReadOffline_Click( object sender, EventArgs e ) { bReadOffline = !bReadOffline; miReadOffline.Checked = bReadOffline; } } }