/// <summary> /// Posts a comment to a newsgroup using NNTP /// </summary> /// <param name="item2post">An NNTP item that will be posted to the website</param> /// <param name="postTarget">An feed that is the post target</param> /// <param name="credentials">Credentials to use</param> /// <returns>The NNTP Status code returned</returns> /// <exception cref="WebException">If an error occurs when the POSTing the /// comment</exception> public static void PostCommentViaNntp(INewsItem item2post, INewsFeed postTarget, ICredentials credentials) { string comment = item2post.ToString(NewsItemSerializationFormat.NntpMessage); Encoding enc = Encoding.UTF8, unicode = Encoding.Unicode; byte[] encBytes = Encoding.Convert(unicode, enc, unicode.GetBytes(comment)); //enc.GetBytes(comment); enough ??? NntpWebRequest request = (NntpWebRequest)WebRequest.Create(postTarget.link); request.Method = "POST"; if (credentials != null) { request.Credentials = credentials; } Stream myWriter = null; try{ myWriter = request.GetRequestStream(); myWriter.Write(encBytes, 0, encBytes.Length); request.GetResponse(); } catch (Exception e) { throw new WebException(e.Message, e); }finally{ if (myWriter != null) { myWriter.Close(); } } }
/// <summary> /// Removes a feed from the cache /// </summary> /// <param name="feed">The feed to remove</param> public override void RemoveFeed(INewsFeed feed) { if (feed == null || feed.cacheurl == null) { return; } string cachelocation = Path.Combine(CacheLocation, feed.cacheurl); string feedContentLocation = Path.Combine(CacheLocation, feed.cacheurl.Substring(0, feed.cacheurl.Length - 4) + ".bin"); try{ if (File.Exists(cachelocation)) { FileHelper.Delete(cachelocation); } if (File.Exists(feedContentLocation)) { FileHelper.Delete(feedContentLocation); } }catch (IOException iox) { _log.Debug("RemoveFeed: Could not delete " + cachelocation, iox); } }
/// <summary> /// Called to show the small toast alert window on new items received. /// </summary> /// <param name="feed">Feed to be displayed</param> /// <param name="dispItemCount">unread items count to display</param> /// <param name="items">list of the newest DownloadItem's received. We assume, /// they are sorted with the newest items first!</param> /// <remarks> /// The parameter <c>dispItemCount</c> controls, if and how many item links /// are displayed in the window. This means; if 0 (zero) or lower than zero, nothing /// happens (no window). If one or more is specified, it displayes up to three items /// in the window. This way you can control, if there was allready e.g. 3 new items on the /// feed, and just only one new was received, that the window display only a link /// to that one newest item by specify 1 (one) as the parameter. /// </remarks> public void Alert(INewsFeed feed, int dispItemCount, IList <DownloadItem> items) { if (feed == null || dispItemCount < 0 || items == null || items.Count == 0) { return; } int unreadCount = items.Count; var firstItem = items[0]; if (_alertWindow != null && unreadCount > dispItemCount && !_alertWindow.IsOpen(DownloadItemAlertWindowKey)) { UltraDesktopAlertShowWindowInfo windowInfo = new UltraDesktopAlertShowWindowInfo(); windowInfo.Key = DownloadItemAlertWindowKey; windowInfo.Image = Properties.Resources.download_enclosure_32; windowInfo.Data = firstItem; windowInfo.PinButtonVisible = true; windowInfo.Caption = $"<font face=\"Tahoma\" size=\"+2\"><b>{feed.title}</b></font><br/> "; windowInfo.Text = String.Format("<font face=\"Tahoma\">{0}<br/>{1}<br/>{2}</font>", SR.GUIStatusEnclosureJustReceivedItemsMessage, StringHelper.ShortenByEllipsis(firstItem.File.LocalName, maxItemTextWith), String.IsNullOrEmpty(firstItem.Enclosure.Description) ? "" : firstItem.Enclosure.Description); windowInfo.FooterText = $"<font face=\"Tahoma\" size=\"-1\">{SR.MenuShowFeedPropertiesCaption}</font>"; if (_preferences.AllowAppEventSounds) { windowInfo.Sound = Resource.ApplicationSound.GetSoundStream(Resource.ApplicationSound.NewAttachmentDownloaded); } _alertWindow.Show(windowInfo); } }
/// <summary> /// Returns the feed URL and source ID of the optional feed reference element for this <paramref name="newsItem"/>. /// </summary> /// <param name="newsFeed">The news feed.</param> /// <param name="sourceID">out: The source ID. -1 in case no source ID is available</param> /// <returns> /// The feed URL of the source feed if a pointer to it exists and NULL otherwise. /// </returns> public static string GetOriginalFeedReference(INewsFeed newsFeed, out int sourceID) { if (newsFeed == null) { throw new ArgumentNullException("newsFeed"); } sourceID = -1; string feedUrl = null; XmlQualifiedName key = AdditionalElements.GetQualifiedName(OriginalFeedRef); XmlQualifiedName attrKey = AdditionalElements.GetQualifiedName(OriginalSourceID); if (key != null && newsFeed.Any != null && newsFeed.Any.Length > 0) { XmlElement origin = newsFeed.Any[0]; feedUrl = origin.InnerText; if (origin.Attributes.Count > 0) { XmlNode a = origin.Attributes.GetNamedItem(attrKey.Name, attrKey.Namespace); if (a != null) { string fs = a.InnerText; if (!String.IsNullOrEmpty(fs)) { Int32.TryParse(fs, out sourceID); } } } } return(feedUrl); }
public void SaveFeedCreatesCacheFile() { //Load feed list. var cache = new FileStorageDataService(); cache.Initialize(Path.GetFullPath(_cacheDirectory)); var handler = new BanditFeedSource(ConfigurationWithoutSearchIndexerAndUnitTestCache, new SubscriptionLocation(WEBROOT_PATH + @"\NewsHandlerTestFiles\LocalTestFeedList.xml")); handler.LoadFeedlist(); Assert.IsTrue(handler.FeedsListOK, "Feeds should be valid!"); //Grab a feed. INewsFeed feed = handler.GetFeeds()[BASE_URL + @"LocalTestFeed.xml"]; //feedsFeed feed = handler.FeedsTable[NewsHandlerTests.BASE_URL + "LocalTestFeed.xml"]; Console.WriteLine("CACHEURL: " + feed.cacheurl); FileInfo cachedFile = new FileInfo(Path.Combine(_cacheDirectory, feed.cacheurl)); DateTime lastWriteTime = cachedFile.LastWriteTime; Assert.IsNotNull(handler.GetFeedDetails(feed.link), "Feed info should not be null."); //Save the cache. Thread.Sleep(1000); handler.ApplyFeedModifications(feed.link); Assert.IsTrue(cache.FeedExists(feed), "The feed should have been saved to the cache"); string[] files = Directory.GetFiles(_cacheDirectory); Assert.IsTrue(files.Length > 0, "There should be at least one cache file in the cache."); cachedFile = new FileInfo(Path.Combine(_cacheDirectory, feed.cacheurl)); Assert.IsTrue(cachedFile.LastWriteTime > lastWriteTime, "Didn't overwrite the file. Original: " + lastWriteTime + " New: " + cachedFile.LastWriteTime); }
/// <summary> /// Helper to create a wrapped Exception, that provides more error infos for a feed /// </summary> /// <param name="e">The exception.</param> /// <param name="f">The feed.</param> /// <param name="entry">The entry.</param> /// <returns></returns> static FeedRequestException CreateLocalFeedRequestException(Exception e, INewsFeed f, FeedSourceEntry entry) { if (entry != null) { return(new FeedRequestException(e.Message, e, entry.Source.GetFailureContext(f))); } return(new FeedRequestException(e.Message, e, new Hashtable())); }
/// <summary> /// Gets the source of a <paramref name="newsFeed"/>. /// </summary> /// <param name="newsFeed">The news feed.</param> /// <returns></returns> public FeedSourceEntry SourceOf(INewsFeed newsFeed) { if (newsFeed == null) { return(null); } return(_feedSources.Values.FirstOrDefault(id => ReferenceEquals(id.Source, newsFeed.owner))); }
public PostReplyEventArgs(INewsFeed postToFeed, string title, string name, string url, string email, string comment, bool beautify) { this.PostToFeed = postToFeed; this.FromName = name; this.FromUrl = url; this.FromEMail = email; this.Comment = comment; this.Title = title; this.Beautify = beautify; }
/// <summary> /// Gets the value of a particular wildcard element. If the element is not found then /// null is returned /// </summary> /// <param name="f">The f.</param> /// <param name="namespaceUri">The namespace URI.</param> /// <param name="localName">Name of the local.</param> /// <returns> /// The value of the wildcard element obtained by calling XmlElement.InnerText /// or null if the element is not found. /// </returns> public static string GetElementWildCardValue(INewsFeed f, string namespaceUri, string localName) { foreach (XmlElement element in f.Any) { if (element.LocalName == localName && element.NamespaceURI == namespaceUri) { return(element.InnerText); } } return(null); }
/// <summary> /// Gets the source extension. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="newsFeed">The news feed.</param> /// <returns>Null, if <paramref name="newsFeed"/> is null, else the requested extension instance</returns> /// <exception cref="InvalidCastException">If extension is not implemented by the <c>newsFeed</c> source</exception> public T GetSourceExtension <T>(INewsFeed newsFeed) { FeedSourceEntry sid = SourceOf(newsFeed); if (sid != null) { object t = sid.Source; return((T)t); } return(default(T)); }
public static Image GetImage(FeedSource source, INewsFeed feed) { if (feed == null || source == null) { return(null); } if (!source.FeedHasFavicon(feed)) { return(null); } var id = feed.favicon; Uri faviconUri; if (Uri.TryCreate(feed.link, UriKind.Absolute, out faviconUri)) { id = "{0}/{1}".FormatWith(faviconUri.Authority, feed.favicon); } Image image; if (_favicons.TryGetValue(id, out image)) { return(image); } try { byte[] imageData = source.GetFaviconForFeed(feed); if (ImageDataAreResized(ref imageData, feed.favicon, out image)) { // save resized image data to permanent store: source.SetFaviconForFeed(feed, feed.favicon, imageData); } } catch (Exception ex) { _log.Error("Failed in GetImage({0}); id = {1}".FormatWith(feed.link, id), ex); } lock (_favicons) { if (!_favicons.ContainsKey(id)) { _favicons.Add(id, image); } } return(image); }
public static bool IsSecuredFeed(INewsFeed feed) { if (feed == null || string.IsNullOrEmpty(feed.link)) { return(false); } if (feed.authUser != null || feed.link.StartsWith("https")) { return(true); } return(false); }
/// <summary> /// Initializes the class from an INewsFeed instance /// </summary> /// <param name="feedtoclone">The feed to obtain it's properties from</param> public NewsFeed(INewsFeed feedtoclone) { if (feedtoclone != null) { this.link = feedtoclone.link; this.title = feedtoclone.title; this.category = feedtoclone.category; this.cacheurl = cacheurl; this.storiesrecentlyviewed = new List <string>(feedtoclone.storiesrecentlyviewed); this.deletedstories = new List <string>(feedtoclone.deletedstories); this.id = feedtoclone.id; this.lastretrieved = feedtoclone.lastretrieved; this.lastretrievedSpecified = feedtoclone.lastretrievedSpecified; this.lastmodified = feedtoclone.lastmodified; this.lastmodifiedSpecified = feedtoclone.lastmodifiedSpecified; this.authUser = feedtoclone.authUser; this.authPassword = feedtoclone.authPassword; this.downloadenclosures = feedtoclone.downloadenclosures; this.downloadenclosuresSpecified = feedtoclone.downloadenclosuresSpecified; this.enclosurefolder = feedtoclone.enclosurefolder; this.replaceitemsonrefresh = feedtoclone.replaceitemsonrefresh; this.replaceitemsonrefreshSpecified = feedtoclone.replaceitemsonrefreshSpecified; this.refreshrate = feedtoclone.refreshrate; this.refreshrateSpecified = feedtoclone.refreshrateSpecified; this.maxitemage = feedtoclone.maxitemage; this.etag = feedtoclone.etag; this.markitemsreadonexit = feedtoclone.markitemsreadonexit; this.markitemsreadonexitSpecified = feedtoclone.markitemsreadonexitSpecified; this.listviewlayout = feedtoclone.listviewlayout; this.favicon = feedtoclone.favicon; this.stylesheet = feedtoclone.stylesheet; this.enclosurealert = feedtoclone.enclosurealert; this.enclosurealertSpecified = feedtoclone.enclosurealertSpecified; this.alertEnabled = feedtoclone.alertEnabled; this.alertEnabledSpecified = feedtoclone.alertEnabledSpecified; if (feedtoclone.Any != null) { this.Any = new XmlElement[feedtoclone.Any.Length]; feedtoclone.Any.CopyTo(this.Any, 0); } if (feedtoclone.AnyAttr != null) { this.AnyAttr = new XmlAttribute[feedtoclone.AnyAttr.Length]; feedtoclone.AnyAttr.CopyTo(this.AnyAttr, 0); } } }
// /// <summary> // /// Re-Index a feed. First, the feed gets removed completely from index, // /// then the items are added to index again. // /// </summary> // /// <param name="feedID">The feed URL.</param> // /// <param name="newsItems">The news items.</param> // public void ReIndex(string feedID, IList newsItems) { // if (!UseIndex) return; // //WASTODO: way too general, we should optimize that: // // re-indexing only the really new items, and remove only // // the purged items: // this.IndexRemove(feedID); // this.IndexAdd(newsItems); // } /// <summary> /// Re-Index a feed. First, the feed gets removed completely from index, /// then the items are added to index again. /// </summary> /// <param name="feed">The feed.</param> /// <param name="items">The NewsItems belonging to the feed</param> public void ReIndex(INewsFeed feed, IList <INewsItem> items) { if (!UseIndex || feed == null) { return; } try { LuceneIndexer indexer = GetIndexer(); indexer.RemoveNewsItems(feed.id); indexer.IndexNewsItems(items); } catch (Exception ex) { Log.Error("Failure while ReIndex item(s) in search index.", ex); } //this.IndexRemove(feed.id); //this.IndexAdd(newsHandler.GetCachedItemsForFeed(feed.link)); }
/// <summary> /// Returns an RSS feed. /// </summary> /// <param name="feed">The feed whose FeedInfo is required.</param> /// <returns>The requested feed or null if it doesn't exist</returns> public override IInternalFeedDetails GetFeed(INewsFeed feed) { if (null == feed || null == feed.cacheurl) { return(null); } IInternalFeedDetails fi = null; string cachelocation = Path.Combine(CacheLocation, feed.cacheurl); if (File.Exists(cachelocation)) { using (Stream feedStream = FileHelper.OpenForRead(cachelocation)) { fi = RssParser.GetItemsForFeed(feed, feedStream, true); } this.LoadItemContent(fi); } return(fi); }
/// <summary> /// Converts the input comments and list of users into a collection of INewsItem objects. /// </summary> /// <param name="feed">The parent news feed of the item whose comments are being generated</param> /// <param name="feedDetails">The parent feed details object for the comments being generated</param> /// <param name="comments">The comments from Facebook</param> /// <param name="users">The list of users who posted the comments </param> /// <returns>A list of news items representing the Facebook comments</returns> private static List <INewsItem> CreateCommentNewsItems(INewsFeed feed, IFeedDetails feedDetails, List <FacebookComment> comments, List <FacebookUser> users) { string htmlBody = @"<div class='comment_box'><div class='ufi_section'> <div class='comment_profile_pic'> <a title='{0}' href='{1}'> <span class='UIRoundedImage UIRoundedImage_Small'><img class='UIRoundedImage_Image' src='{2}' /></span> </a> </div> <div class='comment_content'> <div class='comment_actions'> <a href='{1}'>{0}</a> - <span class='comment_meta_data'>{3}</span> </div> <div class='comment_text'><div class='comment_actual_text'>{4}</div> </div> </div>"; List <INewsItem> items = new List <INewsItem>(); foreach (FacebookComment c in comments) { FacebookUser u = users.FirstOrDefault(user => user.uid == c.fromid.ToString()); DateTime pubdate = ConvertFromUnixTimestamp(c.time); //handle situations where all nulls returned because commenter isn't viewer's friend or in their network string name = String.IsNullOrEmpty(u.firstname) && String.IsNullOrEmpty(u.lastname) ? ComponentsText.FacebookUnknownUser : u.firstname + " " + u.lastname; u.picsquare = u.picsquare ?? DefaultFacebookProfilePic; u.profileurl = u.profileurl ?? DefaultFacebookProfileUrl; string content = String.Format(htmlBody, name, u.profileurl, u.picsquare, pubdate.ToString("h:mmtt MMM dd"), c.text); NewsItem n = new NewsItem(feed, String.Empty, String.Empty, content, pubdate, String.Empty); n.Author = name; n.FeedDetails = feedDetails; n.Id = c.id; items.Add(n); } return(items); }
public NewsFeedController(ILogger <NewsFeedController> logger, INewsFeed newsFeed) { _logger = logger; _newsFeedService = newsFeed; }
public static Image GetImage(FeedSource source, INewsFeed feed) { if (feed == null || source == null) { return(null); } if (!source.FeedHasFavicon(feed)) { return(null); } var id = feed.favicon; Uri faviconUri; if (Uri.TryCreate(feed.link, UriKind.Absolute, out faviconUri)) { id = $"{faviconUri.Authority}/{feed.favicon}"; } Image image = null; try { if (_favicons.TryGetValue(id, out image)) { // Ensure they're valid var w = image.Width; var h = image.Height; return(image); } byte[] imageData = source.GetFaviconForFeed(feed); if (ImageDataAreResized(ref imageData, feed.favicon, out image)) { // save resized image data to permanent store: source.SetFaviconForFeed(feed, feed.favicon, imageData); // Ensure they're valid var w = image.Width; var h = image.Height; } } catch (Exception ex) { _log.Error($"Failed in GetImage({feed.link}); id = {id}", ex); } lock (_favicons) { if (!_favicons.ContainsKey(id) && image != null) { _favicons.Add(id, image); } } return(image); }
/// <summary> /// Returns an RSS feed as an XmlReader. /// </summary> /// <param name="feed">The feed whose FeedInfo is required.</param> /// <returns>The requested feed</returns> public abstract IInternalFeedDetails GetFeed(INewsFeed feed);
/// <summary> /// Initializes a new instance of the <see cref="PostReplyThreadHandler"/> class. /// </summary> /// <param name="feedHandler">The feed handler.</param> /// <param name="item2post">The item2post.</param> /// <param name="postTarget">The post target.</param> public PostReplyThreadHandler(FeedSource feedHandler, INewsItem item2post, INewsFeed postTarget) { this.feedHandler = feedHandler; this.item2post = item2post; this.postTarget = postTarget; }
/// <summary> /// Helper to create a wrapped Exception, that provides more error infos for a feed /// </summary> /// <param name="e">Exception</param> /// <param name="f">NewsFeed</param> /// <param name="fi">IFeedDetails</param> /// <returns></returns> internal static FeedRequestException CreateLocalFeedRequestException(Exception e, INewsFeed f, IFeedDetails fi) { return(new FeedRequestException(e.Message, e, FeedSource.CreateFailureContext(f, fi))); }
public NewsFeedTest() { _feed = new NewsFeed(); }
/// <summary> /// Tests whether a feed with the given ID exists in the cache /// </summary> /// <param name="feed">The feed</param> /// <returns>True if a feed with that ID exists in the cache</returns> public override bool FeedExists(INewsFeed feed) { string cachelocation = Path.Combine(CacheLocation, feed.cacheurl); return(File.Exists(cachelocation)); }
/// <summary> /// Removes a feed from the cache /// </summary> /// <param name="feed">The feed to remove</param> public abstract void RemoveFeed(INewsFeed feed);
/// <summary> /// Gets the source type of an item. /// </summary> /// <param name="newsFeed">The news feed.</param> /// <returns></returns> public FeedSourceType SourceTypeOf(INewsFeed newsFeed) { FeedSourceEntry sid = SourceOf(newsFeed); return(sid != null ? sid.Source.Type : FeedSourceType.Unknown); }
/// <summary> /// Tests whether a feed with the given ID exists in the cache /// </summary> /// <param name="feed">The feed being searched for</param> /// <returns>True if a feed with that ID exists in the cache</returns> public abstract bool FeedExists(INewsFeed feed);
/// <summary> /// Executes a search. /// </summary> /// <param name="criteria">The criteria.</param> /// <param name="scope">The scope.</param> /// <param name="feedSources">The news handlers.</param> /// <param name="cultureName">Name of the culture.</param> /// <returns></returns> public Result ExecuteSearch(SearchCriteriaCollection criteria, INewsFeed[] scope, IEnumerable <FeedSource> feedSources, string cultureName) { if (!UseIndex) { return(null); } Query q = BuildLuceneQuery(criteria, scope, GetAnalyzer(cultureName)); if (q == null) // not validated { return(new Result(0, 0, GetList <SearchHitNewsItem> .Empty, GetArrayList.Empty)); } //TODO: to be fixed - // next line causes issues with concurrent thread access to the search index: IndexSearcher searcher = new IndexSearcher(this._settings.GetIndexDirectory()); Hits hits = null; while (hits == null) { try { DateTime start = DateTime.Now; hits = searcher.Search(q, Sort.RELEVANCE); TimeSpan timeRequired = TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks); _log.Info(String.Format("Found {0} document(s) that matched query '{1}' (time required: {2})", hits.Length(), q, timeRequired)); } catch (BooleanQuery.TooManyClauses) { BooleanQuery.SetMaxClauseCount(BooleanQuery.GetMaxClauseCount() * 2); _log.Info(String.Format("Search failed with error 'BooleanQuery.TooManyClauses'. Retry with BooleanQuery.MaxClauseCount == {0}", BooleanQuery.GetMaxClauseCount())); } } List <SearchHitNewsItem> items = new List <SearchHitNewsItem>(hits.Length()); HybridDictionary matchedFeeds = new HybridDictionary(); for (int i = 0; i < hits.Length(); i++) { Document doc = hits.Doc(i); INewsFeed f = null; string feedLink = doc.Get(Keyword.FeedLink); if (matchedFeeds.Contains(feedLink)) { f = (INewsFeed)matchedFeeds[feedLink]; } if (f == null) { foreach (FeedSource h in feedSources) { if (h.IsSubscribed(feedLink)) { f = h.GetFeeds()[feedLink]; break; } } } if (f == null) { continue; } SearchHitNewsItem item = new SearchHitNewsItem(f, doc.Get(Keyword.ItemTitle), doc.Get(Keyword.ItemLink), doc.Get(IndexDocument.ItemSummary), doc.Get(Keyword.ItemAuthor), new DateTime(DateTools.StringToTime(doc.Get(Keyword.ItemDate))), LuceneNewsItemSearch.NewsItemIDFromUID(doc.Get(IndexDocument.ItemID))); items.Add(item); if (!matchedFeeds.Contains(feedLink)) { matchedFeeds.Add(feedLink, f); } } return(new Result(items.Count, matchedFeeds.Count, items, new ArrayList(matchedFeeds.Values))); }
public NewsController(INewsFeed newsFeed) { _newsFeed = newsFeed; }
/// <summary> /// Reads the list of articles from the stream and returns the feed item. /// </summary> /// <param name="f">Information about the feed. This information is updated based /// on the results of processing the feed.</param> /// <param name="newsgroupListStream">A stream containing an nntp news group list.</param> /// <param name="response">The response.</param> /// <param name="cacheDataService">The cache data service to store embedded binary content.</param> /// <param name="cachedStream">Flag states update last retrieved date on feed only /// if the item was not cached. Indicates whether the lastretrieved date is updated /// on the NewsFeed object passed in.</param> /// <returns> /// A FeedInfo containing the NewsItem objects /// </returns> internal static FeedInfo GetItemsForNewsGroup(INewsFeed f, Stream newsgroupListStream, WebResponse response, IUserCacheDataService cacheDataService, bool cachedStream) { int readItems = 0; List <INewsItem> items = new List <INewsItem>(); NewsItem item; StringBuilder content = new StringBuilder(); #if DEBUG // just to have the source for the item to build to track down issues: StringBuilder itemSource = new StringBuilder(); #endif NntpWebResponse nntpResponse = (NntpWebResponse)response; FeedInfo fi = new FeedInfo(f.id, f.cacheurl, items, f.title, f.link, String.Empty); try { foreach (MimeMessage msg in nntpResponse.Articles) { string parentId; string id; string author = parentId = id = null; DateTime pubDate = DateTime.UtcNow; content.Length = 0; string title; if (msg.Subject != null) { title = EscapeXML(msg.Subject.Value); } else { title = ""; } UnstructuredField fld = msg.Header.GetField(MimeField.MessageID) as UnstructuredField; if (fld != null) { id = fld.Value; } MailboxListField mfld = msg.Header.GetField(MimeField.From) as MailboxListField; if (mfld != null && mfld.MailboxList.Count > 0) { author = mfld.MailboxList[0].AddressString; } fld = msg.Header.GetField(MimeField.References) as UnstructuredField; if (fld != null) { // returns the hierarchy path: the last one is our real parent: string[] singleRefs = fld.Value.Split(' '); if (singleRefs.Length > 0) { parentId = CreateGoogleUrlFromID(singleRefs[singleRefs.Length - 1]); } } DateTimeField dfld = msg.Header.GetField(MimeField.Date) as DateTimeField; if (dfld != null) { pubDate = dfld.DateValue; } ITextBody txtBody = msg.Body as ITextBody; if (txtBody != null) { content.Append(txtBody.Reader.ReadToEnd()); content = NntpClient.DecodeBody(content, (fileName, bytes) => { string name = PrepareEmbeddedFileUrl(fileName, id, nntpResponse.ResponseUri); // we replace the uuencoded/yencoded binary content with a clickable link: if (IsImage(fileName)) { return(String.Format("<img src='{1}' alt='{0}'></img>", fileName, cacheDataService.SaveBinaryContent(name, bytes).AbsoluteUri)); } return(String.Format("<a href='{1}'>{0}</a>", fileName, cacheDataService.SaveBinaryContent(name, bytes).AbsoluteUri)); }, line => { // escape HTML/XML special chars: return(line.Replace("<", "<").Replace("]]>", "]]>")); }); content = content.Replace(Environment.NewLine, "<br>"); } if (id != null) { item = new NewsItem(f, title, CreateGoogleUrlFromID(id), content.ToString(), author, pubDate, id, parentId); item.FeedDetails = fi; item.CommentStyle = SupportedCommentStyle.NNTP; item.Enclosures = Collections.GetList <IEnclosure> .Empty; items.Add(item); FeedSource.ReceivingNewsChannelServices.ProcessItem(item); } else { #if DEBUG _log.Warn("No message-id header found for item:\r\n" + itemSource.ToString()); #else _log.Warn("No message-id header found for item."); #endif } } //update last retrieved date on feed only if the item was not cached.) if (!cachedStream) { f.lastretrieved = new DateTime(DateTime.Now.Ticks); f.lastretrievedSpecified = true; } //any new items in feed? if ((items.Count == 0) || (readItems == items.Count)) { f.containsNewMessages = false; } else { f.containsNewMessages = true; } FeedSource.ReceivingNewsChannelServices.ProcessItem(fi); FeedSource.RelationCosmosAddRange(items); fi.itemsList.AddRange(items); } catch (Exception e) { _log.Error("Retriving NNTP articles from " + nntpResponse.ResponseUri + " caused an exception", e); } return(fi); }