/// <summary> /// Refresh the items of a single feed. It doesn't save the new items! /// </summary> /// <param name="feed"></param> public void RefreshFeedContents(Feed feed) { feed.FeedItems.Clear(); try { XmlDocument doc = GetFeedXml(feed.Url); // Create an XmlNamespaceManager for resolving namespaces. XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("dc", "http://purl.org/dc/elements/1.1/"); XmlNodeList xmlItems = doc.SelectNodes("//channel/item"); foreach (XmlNode xmlItem in xmlItems) { FeedItem feedItem = new FeedItem(); // Truncate title to 100 characters string title = xmlItem.SelectSingleNode("title").InnerText; if (title.Length > 100) { title = title.Substring(0, 100); } feedItem.Title = title; feedItem.Url = xmlItem.SelectSingleNode("link").InnerText; if (xmlItem.SelectSingleNode("pubDate") != null) { feedItem.PubDate = RFC2822Date.Parse(xmlItem.SelectSingleNode("pubDate").InnerText); } else { feedItem.PubDate = DateTime.Now; } if (this._showContents && xmlItem.SelectSingleNode("description") != null) { feedItem.Content = xmlItem.SelectSingleNode("description").InnerText; } if (xmlItem.SelectSingleNode("author", nsmgr) != null) { feedItem.Author = xmlItem.SelectSingleNode("author", nsmgr).InnerText; } else if (xmlItem.SelectSingleNode("dc:creator", nsmgr) != null) { feedItem.Author = xmlItem.SelectSingleNode("dc:creator", nsmgr).InnerText; } feedItem.Feed = feed; feed.FeedItems.Add(feedItem); } feed.SortAndFilter(); } catch (Exception ex) { log.Error("Error refreshing feed contents for: " + feed.Title, ex); throw; } }
/// <summary> /// Mail-To-Weblog runs in background thread and this is the thread function. /// </summary> public void Run() { IBlogDataService dataService = null; ILoggingDataService loggingService = null; SiteConfig siteConfig = SiteConfig.GetSiteConfig(configPath); loggingService = LoggingDataServiceFactory.GetService(logPath); dataService = BlogDataServiceFactory.GetService(contentPath, loggingService); ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info, "MailToWeblog thread spinning up"); loggingService.AddEvent(new EventDataItem(EventCodes.Pop3ServiceStart, "", "")); do { try { // reload on every cycle to get the current settings siteConfig = SiteConfig.GetSiteConfig(configPath); loggingService = LoggingDataServiceFactory.GetService(logPath); dataService = BlogDataServiceFactory.GetService(contentPath, loggingService); if (siteConfig.EnablePop3 && siteConfig.Pop3Server != null && siteConfig.Pop3Server.Length > 0 && siteConfig.Pop3Username != null && siteConfig.Pop3Username.Length > 0) { Pop3 pop3 = new Pop3(); try { pop3.host = siteConfig.Pop3Server; pop3.userName = siteConfig.Pop3Username; pop3.password = siteConfig.Pop3Password; pop3.Connect(); pop3.Login(); pop3.GetAccountStat(); for (int j = pop3.messageCount; j >= 1; j--) { Pop3Message message = pop3.GetMessage(j); string messageFrom; // [email protected] 1-MAR-04 // only delete those messages that are processed bool messageWasProcessed = false; // E-Mail addresses look usually like this: // My Name <*****@*****.**> or simply // [email protected]. This block handles // both variants. Regex getEmail = new Regex(".*\\<(?<email>.*?)\\>.*"); Match matchEmail = getEmail.Match(message.from); if (matchEmail.Success) { messageFrom = matchEmail.Groups["email"].Value; } else { messageFrom = message.from; } // Only if the subject of the message is prefixed (case-sensitive) with // the configured subject prefix, we accept the message if (message.subject.StartsWith(siteConfig.Pop3SubjectPrefix)) { Entry entry = new Entry(); entry.Initialize(); entry.Title = message.subject.Substring(siteConfig.Pop3SubjectPrefix.Length); entry.Categories = ""; entry.Content = ""; entry.Author = messageFrom; //store the email, what we have for now... // Grab the categories. Categories are defined in square brackets // in the subject line. Regex categoriesRegex = new Regex("(?<exp>\\[(?<cat>.*?)\\])"); foreach (Match match in categoriesRegex.Matches(entry.Title)) { entry.Title = entry.Title.Replace(match.Groups["exp"].Value, ""); entry.Categories += match.Groups["cat"].Value + ";"; } entry.Title = entry.Title.Trim(); string categories = ""; string[] splitted = entry.Categories.Split(';'); for (int i = 0; i < splitted.Length; i++) { categories += splitted[i].Trim() + ";"; } entry.Categories = categories.TrimEnd(';'); entry.CreatedUtc = RFC2822Date.Parse(message.date); #region PLain Text // plain text? if (message.contentType.StartsWith("text/plain")) { entry.Content += message.body; } #endregion #region Just HTML // Luke Latimer 16-FEB-2004 ([email protected]) // HTML only emails were not appearing else if (message.contentType.StartsWith("text/html")) { string messageText = ""; // Note the email may still be encoded //messageText = QuotedCoding.DecodeOne(message.charset, "Q", message.body); messageText = message.body; // Strip the <body> out of the message (using code from below) Regex bodyExtractor = new Regex("<body.*?>(?<content>.*)</body>", RegexOptions.IgnoreCase | RegexOptions.Singleline); Match match = bodyExtractor.Match(messageText); if (match != null && match.Success && match.Groups["content"] != null) { entry.Content += match.Groups["content"].Value; } else { entry.Content += messageText; } } #endregion // HTML/Text with attachments ? else if ( message.contentType.StartsWith("multipart/alternative") || message.contentType.StartsWith("multipart/related") || message.contentType.StartsWith("multipart/mixed")) { Hashtable embeddedFiles = new Hashtable(); ArrayList attachedFiles = new ArrayList(); foreach (Attachment attachment in message.attachments) { // just plain text? if (attachment.contentType.StartsWith("text/plain")) { entry.Content += StringOperations.GetString(attachment.data); } // Luke Latimer 16-FEB-2004 ([email protected]) // Allow for html-only attachments else if (attachment.contentType.StartsWith("text/html")) { // Strip the <body> out of the message (using code from below) Regex bodyExtractor = new Regex("<body.*?>(?<content>.*)</body>", RegexOptions.IgnoreCase | RegexOptions.Singleline); string htmlString = StringOperations.GetString(attachment.data); Match match = bodyExtractor.Match(htmlString); //NOTE: We will BLOW AWAY any previous content in this case. // This is because most mail clients like Outlook include // plain, then HTML. We will grab plain, then blow it away if // HTML is included later. if (match != null && match.Success && match.Groups["content"] != null) { entry.Content = match.Groups["content"].Value; } else { entry.Content = htmlString; } } // or alternative text ? else if (attachment.contentType.StartsWith("multipart/alternative")) { bool contentSet = false; string textContent = null; foreach (Attachment inner_attachment in attachment.attachments) { // we prefer HTML if (inner_attachment.contentType.StartsWith("text/plain")) { textContent = StringOperations.GetString(inner_attachment.data); } else if (inner_attachment.contentType.StartsWith("text/html")) { Regex bodyExtractor = new Regex("<body.*?>(?<content>.*)</body>", RegexOptions.IgnoreCase | RegexOptions.Singleline); string htmlString = StringOperations.GetString(inner_attachment.data); Match match = bodyExtractor.Match(htmlString); if (match != null && match.Success && match.Groups["content"] != null) { entry.Content += match.Groups["content"].Value; } else { entry.Content += htmlString; } contentSet = true; } } if (!contentSet) { entry.Content += textContent; } } // or text with embeddedFiles (in a mixed message only) else if ((message.contentType.StartsWith("multipart/mixed") || message.contentType.StartsWith("multipart/alternative")) && attachment.contentType.StartsWith("multipart/related")) { foreach (Attachment inner_attachment in attachment.attachments) { // just plain text? if (inner_attachment.contentType.StartsWith("text/plain")) { entry.Content += StringOperations.GetString(inner_attachment.data); } else if (inner_attachment.contentType.StartsWith("text/html")) { Regex bodyExtractor = new Regex("<body.*?>(?<content>.*)</body>", RegexOptions.IgnoreCase | RegexOptions.Singleline); string htmlString = StringOperations.GetString(inner_attachment.data); Match match = bodyExtractor.Match(htmlString); if (match != null && match.Success && match.Groups["content"] != null) { entry.Content += match.Groups["content"].Value; } else { entry.Content += htmlString; } } // or alternative text ? else if (inner_attachment.contentType.StartsWith("multipart/alternative")) { bool contentSet = false; string textContent = null; foreach (Attachment inner_inner_attachment in inner_attachment.attachments) { // we prefer HTML if (inner_inner_attachment.contentType.StartsWith("text/plain")) { textContent = StringOperations.GetString(inner_inner_attachment.data); } else if (inner_inner_attachment.contentType.StartsWith("text/html")) { Regex bodyExtractor = new Regex("<body.*?>(?<content>.*)</body>", RegexOptions.IgnoreCase | RegexOptions.Singleline); string htmlString = StringOperations.GetString(inner_inner_attachment.data); Match match = bodyExtractor.Match(htmlString); if (match != null && match.Success && match.Groups["content"] != null) { entry.Content += match.Groups["content"].Value; } else { entry.Content += htmlString; } contentSet = true; } } if (!contentSet) { entry.Content += textContent; } } // any other inner_attachment else if (inner_attachment.data != null && inner_attachment.fileName != null && inner_attachment.fileName.Length > 0) { if (inner_attachment.contentID.Length > 0) { embeddedFiles.Add(inner_attachment.contentID, StoreAttachment(inner_attachment, binariesPath)); } else { attachedFiles.Add(StoreAttachment(inner_attachment, binariesPath)); } } } } // any other attachment else if (attachment.data != null && attachment.fileName != null && attachment.fileName.Length > 0) { if (attachment.contentID.Length > 0 && message.contentType.StartsWith("multipart/related")) { embeddedFiles.Add(attachment.contentID, StoreAttachment(attachment, binariesPath)); } else { attachedFiles.Add(StoreAttachment(attachment, binariesPath)); } } } // check for orphaned embeddings string[] embeddedKeys = new string[embeddedFiles.Keys.Count]; embeddedFiles.Keys.CopyTo(embeddedKeys, 0); foreach (string key in embeddedKeys) { if (entry.Content.IndexOf("cid:" + key.Trim('<', '>')) == -1) { object file = embeddedFiles[key]; embeddedFiles.Remove(key); attachedFiles.Add(file); } } // now fix up the URIs if (siteConfig.Pop3InlineAttachedPictures) { foreach (string fileName in attachedFiles) { string fileNameU = fileName.ToUpper(); if (fileNameU.EndsWith(".JPG") || fileNameU.EndsWith(".JPEG") || fileNameU.EndsWith(".GIF") || fileNameU.EndsWith(".PNG") || fileNameU.EndsWith(".BMP")) { bool scalingSucceeded = false; if (siteConfig.Pop3InlinedAttachedPicturesThumbHeight > 0) { try { string absoluteFileName = Path.Combine(binariesPath, fileName); string thumbBaseFileName = Path.GetFileNameWithoutExtension(fileName) + "-thumb.dasblog.JPG"; string thumbFileName = Path.Combine(binariesPath, thumbBaseFileName); Bitmap sourceBmp = new Bitmap(absoluteFileName); if (sourceBmp.Height > siteConfig.Pop3InlinedAttachedPicturesThumbHeight) { Bitmap targetBmp = new Bitmap(sourceBmp, new Size( Convert.ToInt32(Math.Round((((double)sourceBmp.Width) * (((double)siteConfig.Pop3InlinedAttachedPicturesThumbHeight) / ((double)sourceBmp.Height))), 0)), siteConfig.Pop3InlinedAttachedPicturesThumbHeight)); ImageCodecInfo codecInfo = GetEncoderInfo("image/jpeg"); Encoder encoder = Encoder.Quality; EncoderParameters encoderParams = new EncoderParameters(1); long compression = 75; EncoderParameter encoderParam = new EncoderParameter(encoder, compression); encoderParams.Param[0] = encoderParam; targetBmp.Save(thumbFileName, codecInfo, encoderParams); string absoluteUri = new Uri(binariesBaseUri, fileName).AbsoluteUri; string absoluteThumbUri = new Uri(binariesBaseUri, thumbBaseFileName).AbsoluteUri; entry.Content += String.Format("<div class=\"inlinedMailPictureBox\"><a href=\"{0}\"><img border=\"0\" class=\"inlinedMailPicture\" src=\"{2}\"></a><br /><a class=\"inlinedMailPictureLink\" href=\"{0}\">{1}</a></div>", absoluteUri, fileName, absoluteThumbUri); scalingSucceeded = true; } } catch { } } if (!scalingSucceeded) { string absoluteUri = new Uri(binariesBaseUri, fileName).AbsoluteUri; entry.Content += String.Format("<div class=\"inlinedMailPictureBox\"><img class=\"inlinedMailPicture\" src=\"{0}\"><br /><a class=\"inlinedMailPictureLink\" href=\"{0}\">{1}</a></div>", absoluteUri, fileName); } } } } if (attachedFiles.Count > 0) { entry.Content += "<p>"; } foreach (string fileName in attachedFiles) { string fileNameU = fileName.ToUpper(); if (!siteConfig.Pop3InlineAttachedPictures || (!fileNameU.EndsWith(".JPG") && !fileNameU.EndsWith(".JPEG") && !fileNameU.EndsWith(".GIF") && !fileNameU.EndsWith(".PNG") && !fileNameU.EndsWith(".BMP"))) { string absoluteUri = new Uri(binariesBaseUri, fileName).AbsoluteUri; entry.Content += String.Format("Download: <a href=\"{0}\">{1}</a><br />", absoluteUri, fileName); } } if (attachedFiles.Count > 0) { entry.Content += "</p>"; } foreach (string key in embeddedFiles.Keys) { entry.Content = entry.Content.Replace("cid:" + key.Trim('<', '>'), new Uri(binariesBaseUri, (string)embeddedFiles[key]).AbsoluteUri); } } loggingService.AddEvent( new EventDataItem( EventCodes.Pop3EntryReceived, entry.Title, SiteUtilities.GetPermaLinkUrl(siteConfig, entry.EntryId), messageFrom)); SiteUtilities.SaveEntry(entry, siteConfig, loggingService, dataService); ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info, String.Format("Message stored. From: {0}, Title: {1} as entry {2}", messageFrom, entry.Title, entry.EntryId)); // give the XSS upstreamer a hint that things have changed // XSSUpstreamer.TriggerUpstreaming(); // [email protected] (01-MAR-04) messageWasProcessed = true; } else { // [email protected] (01-MAR-04) // logging every ignored email is apt // to fill up the event page very quickly // especially if only processed emails are // being deleted if (siteConfig.Pop3LogIgnoredEmails) { loggingService.AddEvent( new EventDataItem( EventCodes.Pop3EntryIgnored, message.subject, null, messageFrom)); } } // [email protected] (01-MAR-04) if (siteConfig.Pop3DeleteAllMessages || messageWasProcessed) { if (!messageWasProcessed) { loggingService.AddEvent( new EventDataItem( EventCodes.Pop3EntryDiscarded, message.subject, null, messageFrom)); } pop3.DeleteMessage(j); } } } catch (Exception e) { ErrorTrace.Trace(System.Diagnostics.TraceLevel.Error, e); loggingService.AddEvent( new EventDataItem( EventCodes.Pop3ServerError, e.ToString().Replace("\n", "<br />"), null, null)); } finally { pop3.Close(); } } Thread.Sleep(TimeSpan.FromSeconds(siteConfig.Pop3Interval)); } catch (ThreadAbortException abortException) { ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info, abortException); loggingService.AddEvent(new EventDataItem(EventCodes.Pop3ServiceShutdown, "", "")); break; } catch (Exception e) { // if the siteConfig can't be read, stay running regardless // default wait time is 4 minutes in that case Thread.Sleep(TimeSpan.FromSeconds(240)); ErrorTrace.Trace(System.Diagnostics.TraceLevel.Error, e); } }while (true); ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info, "MailToWeblog thread terminating"); loggingService.AddEvent(new EventDataItem(EventCodes.Pop3ServiceShutdown, "", "")); }