/// <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, "", ""));
        }