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