Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
v0.0.0
  • Loading branch information
morkai committed Jan 2, 2014
0 parents commit 16069b7
Show file tree
Hide file tree
Showing 10 changed files with 1,452 additions and 0 deletions.
179 changes: 179 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.

# User-specific files
*.suo
*.user
*.sln.docstates

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
x64/
build/
bld/
[Bb]in/
[Oo]bj/

# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
!packages/*/build/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

#NUNIT
*.VisualState.xml
TestResult.xml

*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile

# Visual Studio profiler
*.psess
*.vsp
*.vspx

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding addin-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# NCrunch
*.ncrunch*
_NCrunch_*
.*crunch*.local.xml

# MightyMoose
*.mm.*
AutoTest.Net/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml

# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
## TODO: If the tool you use requires repositories.config, also uncomment the next line
#!packages/repositories.config

# Windows Azure Build Output
csx/
*.build.csdef

# Windows Store app package directory
AppPackages/

# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm

# SQL Server files
App_Data/*.mdf
App_Data/*.ldf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings

# Microsoft Fakes
FakesAssemblies/

# =========================
# Windows detritus
# =========================

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/
26 changes: 26 additions & 0 deletions EwsMailDl.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C# Express 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EwsMailDl", "EwsMailDl\EwsMailDl.csproj", "{EA83B646-A276-44EB-A735-67D61738531B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EA83B646-A276-44EB-A735-67D61738531B}.Debug|x64.ActiveCfg = Debug|x64
{EA83B646-A276-44EB-A735-67D61738531B}.Debug|x64.Build.0 = Debug|x64
{EA83B646-A276-44EB-A735-67D61738531B}.Debug|x86.ActiveCfg = Debug|x86
{EA83B646-A276-44EB-A735-67D61738531B}.Debug|x86.Build.0 = Debug|x86
{EA83B646-A276-44EB-A735-67D61738531B}.Release|x64.ActiveCfg = Release|x64
{EA83B646-A276-44EB-A735-67D61738531B}.Release|x64.Build.0 = Release|x64
{EA83B646-A276-44EB-A735-67D61738531B}.Release|x86.ActiveCfg = Release|x86
{EA83B646-A276-44EB-A735-67D61738531B}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
190 changes: 190 additions & 0 deletions EwsMailDl/EmailDownloader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.Exchange.WebServices.Data;

namespace EwsMailDl
{
class EmailDownloader
{
private EventLog eventLog;

private List<string> emailIdCache = new List<string>(10);

private CancellationTokenSource tokenSource;

private BlockingCollection<ItemId> emailIdQueue;

private ExchangeService exchangeService;

private string savePath;

private IList<string> subjectFilters;

private bool timestamp;

public EmailDownloader(EventLog eventLog, BlockingCollection<ItemId> emailIdQueue, CancellationTokenSource tokenSource, Settings settings)
{
this.eventLog = eventLog;
this.tokenSource = tokenSource;
this.emailIdQueue = emailIdQueue;
this.exchangeService = settings.CreateExchangeService();
this.savePath = settings.SavePath;
this.subjectFilters = settings.SubjectFilters;
this.timestamp = settings.Timestamp;
}

public void Run()
{
while (!tokenSource.IsCancellationRequested && !emailIdQueue.IsAddingCompleted)
{
ItemId emailId = null;

try
{
emailId = emailIdQueue.Take(tokenSource.Token);
}
catch (OperationCanceledException)
{
if (tokenSource.IsCancellationRequested)
{
if (Environment.UserInteractive)
{
Console.WriteLine("Downloader cancelled!");
}

break;
}
}

if (emailId == null || emailIdCache.Contains(emailId.UniqueId))
{
if (Environment.UserInteractive)
{
Console.WriteLine("Ignoring a duplicate e-mail: {0}", emailId);
}

continue;
}

if (emailIdCache.Count == emailIdCache.Capacity)
{
emailIdCache.RemoveAt(0);
}

emailIdCache.Add(emailId.UniqueId);

EmailMessage email = null;

try
{
email = EmailMessage.Bind(
exchangeService,
emailId,
new PropertySet(
EmailMessageSchema.Subject,
EmailMessageSchema.Attachments,
EmailMessageSchema.DateTimeReceived
)
);
}
catch (Exception) { }

if (email == null)
{
continue;
}

if (MatchEmail(email))
{
if (Environment.UserInteractive)
{
Console.WriteLine("Processing a new matching e-mail: {0}", email.Subject);
}

DownloadAndDelete(email);
}
else if (Environment.UserInteractive && email != null)
{
Console.WriteLine("Ignoring a not matching e-mail: {0}", email.Subject);
}
}
}

private bool MatchEmail(EmailMessage email)
{
return email.Attachments.Count > 0
&& (subjectFilters.Count == 0 || subjectFilters.Any(phrase => email.Subject.ToLower().Contains(phrase.ToLower())));
}

private void DownloadAndDelete(EmailMessage email)
{
foreach (var attachment in email.Attachments)
{
if (!(attachment is FileAttachment))
{
continue;
}

var fileAttachment = attachment as FileAttachment;

try
{
if (Environment.UserInteractive)
{
Console.WriteLine("Downloading an attachment: {0}", fileAttachment.Name);
}

var filePath = CreateFilePath(email.DateTimeReceived, fileAttachment.Name);

fileAttachment.Load(filePath);
File.SetCreationTime(filePath, email.DateTimeReceived);
}
catch (Exception x)
{
HandleException("Failed to download the attachment", x);
}
}

try
{
if (Environment.UserInteractive)
{
Console.WriteLine("Deleting the e-mail...");
}

email.Delete(DeleteMode.HardDelete);
}
catch (Exception x)
{
HandleException("Failed to delete the e-mail", x);
}
}

private string CreateFilePath(DateTime dateTime, string fileName)
{
if (timestamp)
{
fileName = String.Format("{0}@{1}", (dateTime - new DateTime(1970, 1, 1).ToLocalTime()).TotalSeconds, fileName);
}

return Path.Combine(savePath, fileName);
}

private void HandleException(string prefix, Exception x)
{
if (Environment.UserInteractive)
{
Console.WriteLine(prefix + ": " + x);
}
else
{
this.eventLog.WriteEntry(prefix + ": " + x, EventLogEntryType.Warning);
}
}
}
}
Loading

0 comments on commit 16069b7

Please sign in to comment.