/// <summary> /// Returns the response to the NNTP request /// </summary> /// <param name="asyncRequest">Indicates whether this method is being called as part of /// an async request. This tells us whether to use the Timeout value or not.</param> /// <returns>The NNTP response</returns> private WebResponse GetResponse(bool asyncRequest) { NntpWebResponse response; MemoryStream newsgroupListStream; //The stream is not closed on purpose in this method StreamWriter sw; using (NntpClient client = this.Connect()) { if (!asyncRequest) { client.Timeout = this.Timeout; } switch (this.method) { case "POST": requestStream.Position = 0; client.Post(new UTF8Encoding().GetString(this.requestStream.ToArray())); response = new NntpWebResponse(NntpStatusCode.OK, RequestUri); break; case "LIST": newsgroupListStream = new MemoryStream(); sw = new StreamWriter(newsgroupListStream); client.Groups(sw); sw.Flush(); newsgroupListStream.Position = 0; response = new NntpWebResponse(NntpStatusCode.OK, newsgroupListStream, RequestUri); break; case "NEWNEWS": client.SelectGroup(requestUri.PathAndQuery.Substring(1)); IList <MimeMessage> msgs = client.GetNntpMessages(ifModifiedSince, downloadCount); response = new NntpWebResponse(NntpStatusCode.OK, Stream.Null, RequestUri); response.Articles = msgs; break; default: throw new NotSupportedException(method); } } return(response); }
/// <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); }