void UpdateFeedStatus(string url, string message) { int counter = 0; foreach (System.Xml.XmlNode outlineNode in this._Library.MyFeedsOPMLDocument.DocumentElement.SelectNodes("body/outline")) { string href = RSSLibraryClass.GetOutlineUrl(outlineNode); if (href == url) { // Found it. string listItem = (string)lstFeeds.Items[counter]; if (listItem.EndsWith(")") && listItem.Contains("(")) { listItem = listItem.Substring(0, listItem.LastIndexOf("(")).Trim(); } lstFeeds.Items[counter] = listItem + " (" + _I18N.GetText("Error") + ")"; if (counter == lstFeeds.SelectedIndex) { this.lblStatus.Text = message; } break; } counter++; } if (url == this._Library.currentFeed.Url) { MessageBox.Show(this, "Failed to load feed: " + message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } }
/// <summary> /// Parse HTML into text very stupidly. /// </summary> /// <param name="html">Some HTML mark-up</param> /// <returns>Plain text string</returns> private string TrivialParse(string html) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); Char[] htmlChars = html.ToCharArray(); int parseState = 0;// 0 = output, 1 = don't output, 2 = don't output this character but output next. for (int i = 0; i < htmlChars.Length; i++) { if (htmlChars[i] == '<') { parseState = 1; } else if (htmlChars[i] == '>') { parseState = 2; } else if (parseState == 0) { sb.Append(htmlChars[i]); } if (parseState == 2) { sb.Append(" "); parseState = 0; } } string output = sb.ToString(); while (output.Contains(" ")) { output = output.Replace(" ", " "); } return(RSSLibraryClass.CleanUpXml(output.Trim())); }
/// <summary> /// Create a new item using text obtained from an "item" element in a feed. /// </summary> /// <param name="title">The contents of the "title" element.</param> /// <param name="itemUrl">The contents of the "link" element.</param> /// <param name="feedUrl">The URL of the feed in which this item sits.</param> /// <param name="pubDate">The contents of the "pubDate" element.</param> /// <param name="contents">The contents of the "content" or "content:encoded" or "description" node, which can be HTML.</param> /// <param name="enclosure">The url of an enclosure - an audio or video file found if this is an item in a podcast.</param> public RSSItemClass(string title, string itemUrl, string feedUrl, string pubDate, string contents, string enclosure) { _title = title; // Do character substitutions to catch character escape sequences that have ended up in the data // probably because of an error on the website. I'm sure this list could be extended, but // quotation marks and dashes are the main offenders. _title = RSSLibraryClass.CleanUpXml(_title); _feedUrl = feedUrl; _itemUrl = itemUrl.Replace("\t", "").Replace("\n", "").Trim(); // The Daily Mail feed has tabs and newlines // in the url, so delete and trim. 3.1.2 4 May 2014. DateTime dt; if (DateTime.TryParse(pubDate, out dt)) { _pubDate = dt.ToLongDateString(); if (_pubDate.StartsWith("0")) { // Leading zeros look sucky. _pubDate = _pubDate.Substring(1, _pubDate.Length - 1); } } else { _pubDate = ""; } _contents = TrivialParse(contents); _enclosure = enclosure; }
void UpdateItemCount(string url, int count) { int counter = 0; foreach (System.Xml.XmlNode outlineNode in this._Library.MyFeedsOPMLDocument.DocumentElement.SelectNodes("body/outline")) { string href = RSSLibraryClass.GetOutlineUrl(outlineNode); if (href == url) { // Found it. string listItem = (string)lstFeeds.Items[counter]; if (listItem.EndsWith(")") && listItem.Contains("(")) { listItem = listItem.Substring(0, listItem.LastIndexOf("(")).Trim(); } lstFeeds.Items[counter] = listItem + " (" + count + ")"; } counter++; } }
private void addFeedToolStripMenuItem_Click(object sender, EventArgs e) { string newUrl = Microsoft.VisualBasic.Interaction.InputBox(_I18N.GetText("Enter URL:"), Application.ProductName); if (newUrl.Length == 0) { return; } this.staMain.Text = ""; if (!newUrl.ToLowerInvariant().StartsWith("http")) { // TODO add https? newUrl = "http://" + newUrl; } //The MSDN documentation says it's best to create an XmlTextReader through .Create //rather than = new XmlTextReader. However, if you do it through new, you get an //XmlTextReader that doesn't choke on malformed XML, and if you do it through //.Create you choke on malformed XML. So clearly new is better! System.Xml.XmlTextReader xtr; try { xtr = new System.Xml.XmlTextReader(newUrl); } catch (System.UriFormatException ufe) { // Not a valid URL. Skip trying to analyse. MessageBox.Show(_I18N.GetText("Invalid URL:") + " " + ufe.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); return; } catch (Exception ex) { // Unknown error - File Not Found, possibly - display and quit. MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } string newFeedUrl = ""; string rootNodeName = ""; bool finishedSearching = false; bool readOK = true; while (!xtr.EOF && !finishedSearching && readOK) { try { readOK = xtr.Read(); if (xtr.NodeType == System.Xml.XmlNodeType.Element) { string elementName = xtr.Name.ToLowerInvariant(); // If this is the first node then it is the root node. // Remember the name so that we know what type of document // the user has given us - Atom, RSS, or a web page to // search. System.Diagnostics.Debug.Print("Node:" + elementName); if (rootNodeName.Length == 0) { rootNodeName = elementName; } if (rootNodeName == "html") { // This is an HTML file, scan it for RSS feeds. if (elementName == "link") { // Got a link: is it valid? if (xtr.HasAttributes) { string href = xtr.GetAttribute("href"); string rel = xtr.GetAttribute("rel"); if (rel.ToLowerInvariant() == "alternate" && href != "") { // Got it! newFeedUrl = href; finishedSearching = true; } } } } else if (rootNodeName == "feed" || rootNodeName == "rss") { // It's an RSS/Atom feed, go ahead and add it // without further checking, and stop reading // this document. newFeedUrl = newUrl; finishedSearching = true; } } } catch { //Parsing error from the web page or XML = very common, carry on going //until we find something useful. } System.Windows.Forms.Application.DoEvents(); } xtr.Close(); // OK, so we've examined the url the user gave us. Found anything? if (newFeedUrl == "") { // Failed to find anything! MessageBox.Show(_I18N.GetText("No RSS news feeds found"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); } else { // OK, try getting it. System.Xml.XmlTextReader newFeed = new System.Xml.XmlTextReader(newFeedUrl); string newTitle = ""; string newWebsiteUrl = ""; bool foundTitleAndUrl = false; bool nextNodeIsTitle = false; bool nextNodeIsWebsiteUrl = false; readOK = true; while (!newFeed.EOF && !foundTitleAndUrl && readOK) { try { readOK = newFeed.Read(); if (newFeed.NodeType == System.Xml.XmlNodeType.Element) { System.Diagnostics.Debug.Print("Node:" + newFeed.Name.ToLowerInvariant()); if (newFeed.Name.ToLowerInvariant() == "title") { if (newTitle == "") { nextNodeIsTitle = true; } } else if (newFeed.Name.ToLowerInvariant() == "link") { if (newWebsiteUrl == "") { nextNodeIsWebsiteUrl = true; } } } else if (newFeed.NodeType == System.Xml.XmlNodeType.Text) { if (nextNodeIsTitle) { newTitle = newFeed.Value; nextNodeIsTitle = false; } if (nextNodeIsWebsiteUrl) { newWebsiteUrl = newFeed.Value; nextNodeIsWebsiteUrl = false; } } } catch { // Error in XML, very common, carry on. } if (newTitle.Length > 0 && newWebsiteUrl.Length > 0) { foundTitleAndUrl = true; } System.Windows.Forms.Application.DoEvents(); } newFeed.Close(); // OK, add to lists! if (foundTitleAndUrl) { // Assume this is good. this._Library.AddFeed(newFeedUrl, newTitle, newWebsiteUrl); DisplayFeeds(); lblStatus.Text = _I18N.GetText("Added:") + " " + newTitle; // Set focus to the new feed. try { int i = 0; foreach (System.Xml.XmlNode outline in this._Library.MyFeedsOPMLDocument.DocumentElement.SelectNodes("body/outline")) { string url = RSSLibraryClass.GetOutlineUrl(outline); if (url == newFeedUrl) { lstFeeds.SelectedIndex = i; break; } i++; } } catch { // Fine, didn't set focus, carry on. } try { // Submission of RSS feed to database. newTitle = System.Net.WebUtility.HtmlEncode(newTitle); newUrl = System.Net.WebUtility.HtmlEncode(newUrl); System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("http://data.webbie.org.uk/newRSSFeed.php?title=" + newTitle + "&url=" + newFeedUrl + "&language=" + this._I18N.GetLanguage()); wr.KeepAlive = false; wr.Method = System.Net.WebRequestMethods.Http.Get; wr.ContentType = "text/html"; wr.AllowAutoRedirect = true; wr.GetResponse(); } catch { // Failed to connect and write feed information: record why to error log. System.Diagnostics.EventLog.WriteEntry(Application.ProductName + " " + Application.ProductVersion, "Failed to submit new feed registration to WebbIE (" + newUrl + ")"); } } else { // Not found a feed. staMain.Text = this._I18N.GetText("0 feeds found."); } } }
private void frmMain_Load(object sender, EventArgs e) { //Check for updates. Only do this is WebbIEUpdater.dll is found. This is so that we can do a //build without the updater for the Windows 10 Store. string exeFolder = System.IO.Path.GetDirectoryName(Application.ExecutablePath); if (System.IO.File.Exists(exeFolder + "\\WebbIEUpdater.dll")) { CheckForUpdates(); } // Normal WebbIE I18N code. this._I18N = new I18N(); this._I18N.DoForm(this); // Load the user-subscribed list of feeds. this._Library = new RSSLibraryClass(Environment.CurrentDirectory, Application.UserAppDataPath); this._Library.ItemCountUpdated += _Library_itemCountUpdated; // Handle the events when the user has requested a feed. this._Library.LoadProgress += _Library_LoadProgress; this._Library.LoadFailed += _Library_LoadFailed; this._Library.LoadFinished += _Library_LoadFinished; // Updating previous versions. Check for feeds.xml. This will be located in: string existingFeedFile = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\WebbIE\\AccessibleRSS\\1\\feeds.xml"; if (System.IO.File.Exists(existingFeedFile)) { // We have an existing feed file. Do we need to import it? Have we already? System.IO.FileInfo fi = new System.IO.FileInfo(existingFeedFile); if (fi.LastWriteTimeUtc > RSSNewsReader.Properties.Settings.Default.ImportedPreviousVersionFeeds) { // Need to import. System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); doc.Load(existingFeedFile); foreach (System.Xml.XmlNode node in doc.DocumentElement.SelectNodes("feed")) { // I do not get the webpage url, but I've added code so when it is loaded the htmlUrl // is obtained from the feed XML document. this._Library.AddFeed(node.SelectSingleNode("url").InnerText, node.SelectSingleNode("title").InnerText, ""); } } // Ideally I'd now do the Read section, but I've changed how the settings are saved (why? bad move) // so it's hard so I'm not going to do it. } RSSNewsReader.Properties.Settings.Default.ImportedPreviousVersionFeeds = System.DateTime.UtcNow; // Open any OPML file that's provided and add it to the existing list. if (Environment.GetCommandLineArgs().Length > 1) { // Been passed an OPML file, presumably. string opmlFile = Environment.GetCommandLineArgs()[1]; string url = ""; for (int i = 1; i < Environment.GetCommandLineArgs().Length; i++) { url += Environment.GetCommandLineArgs()[i] + " "; } ImportOPML(url); } this.deletedItemsToolStripMenuItem.Checked = Properties.Settings.Default.ViewDeletedItems; // OK, I have a recurring bug where I end up with duplicates and unsorted feeds, so let's sort it // right now. this._Library.SortFeeds(); this._Library.RemoveDuplicateFeeds(); // Display the current feeds. DisplayFeeds(); if (lstFeeds.Items.Count > 0 && RSSNewsReader.Properties.Settings.Default.SelectedFeedIndex < lstFeeds.Items.Count - 1) { lstFeeds.SelectedIndex = RSSNewsReader.Properties.Settings.Default.SelectedFeedIndex; } if (lstFeeds.SelectedIndex == -1 && lstFeeds.Items.Count > 0) { lstFeeds.SelectedIndex = 0; } // Add sounds to list boxes. ListBoxSounds.AddSounds(this); // Set window state this.WindowState = RSSNewsReader.Properties.Settings.Default.WindowState; // Start the library refreshing the list of read/unread items. this._Library.StartUpdatingFeedCacheInTheBackground(); // Remember that we've done this. this._LastChecked = DateTime.Now; }