// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.Net; using System.IO; using System.Net.Http; using Microsoft.Exchange.WebServices.Data; namespace Spludlow { /// /// Help for EWS Microsoft.Exchange.WebServices /// /// VERY ROUGH CODE !!! Likly to change alot /// public class Exchange { public ExchangeService ExchangeService; private string HostAddress; private string Version; private NetworkCredential NetworkCredential; private ExchangeTraceListener ExchangeTraceListener; public Exchange(string hostAddress, string userName, string password, string domain, string version) { NetworkCredential networkCredential = new NetworkCredential(userName, password, domain); this.Construct(hostAddress, networkCredential, version); } public Exchange(string hostAddress, NetworkCredential networkCredential, string version) { this.Construct(hostAddress, networkCredential, version); } public void Reset() { this.Construct(this.HostAddress, this.NetworkCredential, this.Version); } public void Construct(string hostAddress, NetworkCredential networkCredential, string version) { this.HostAddress = hostAddress; this.NetworkCredential = networkCredential; this.Version = version; string url = "https://" + this.HostAddress + "/EWS/Exchange.asmx"; ExchangeVersion exchangeVersion = (ExchangeVersion)Enum.Parse(typeof(ExchangeVersion), this.Version); this.ExchangeService = new ExchangeService(exchangeVersion); this.ExchangeService.Credentials = this.NetworkCredential; this.ExchangeService.Url = new Uri(url); Spludlow.WebServices.SetServerCertificateValidation(); } public void EnableTrace(bool response, bool request) { TraceFlags flags = TraceFlags.None; if (response == true) flags |= TraceFlags.EwsResponse; if (request == true) flags |= TraceFlags.EwsRequest; this.ExchangeTraceListener = new ExchangeTraceListener(); this.ExchangeService.TraceListener = this.ExchangeTraceListener; this.ExchangeService.TraceFlags = flags; this.ExchangeService.TraceEnabled = true; } public void DisableTrace() { this.ExchangeService.TraceEnabled = false; } public static void TidyXMLNames(DataSet dataSet) { DataSet renameDataSet = Spludlow.Data.ADO.RenameTablesAndColumnsTemplate(dataSet); int index; foreach (DataRow row in renameDataSet.Tables["TableNames"].Rows) { string name = (string)row["SourceTableName"]; while ((index = name.IndexOf(":")) != -1) name = name.Substring(0, index - 1) + name.Substring(index + 1); //name = name.Replace(Spludlow.Data.XML.RelationDelimiter, ""); row["TargetTableName"] = name; } foreach (DataRow row in renameDataSet.Tables["ColumnNames"].Rows) { string name = (string)row["SourceColumnName"]; while ((index = name.IndexOf(":")) != -1) name = name.Substring(0, index - 1) + name.Substring(index + 1); //name = name.Replace(Spludlow.Data.XML.RelationDelimiter, ""); //name = name.Replace(Spludlow.Data.XML.ID_Suffix, "_Id"); row["TargetColumnName"] = name; } Spludlow.Data.ADO.RenameTablesAndColumns(dataSet, renameDataSet); } public static void RelationizeXmlToDatabaseContacts(string xmlFilename, string connectionString, string databaseName, string databaseBackupDirectory) { RelationizeXmlToDatabase(xmlFilename, "t:Contact", connectionString, databaseName, databaseBackupDirectory); } public static void RelationizeXmlToDatabase(string xmlFilename, string topElementname, string connectionString, string databaseName, string databaseBackupDirectory) { DataSet dataSet = Spludlow.Data.XML.ConvertRelational(xmlFilename, topElementname); Spludlow.Exchange.TidyXMLNames(dataSet); DataSet schema = Spludlow.Data.ADO.Schema(dataSet, true); // Fix Empty strings for schema lengths foreach (DataTable table in schema.Tables) { if (table.TableName.EndsWith("_Columns") == false) continue; foreach (DataRow row in table.Select("Longest = 0")) row["Longest"] = 1; } Spludlow.Data.Database.AutoAddForeignKeys(schema); Spludlow.Log.Report("RelationizeXmlToDatabase Schema: " + topElementname, schema); Spludlow.Data.Database.ImportDatabaseUsingTemp(schema, dataSet, connectionString, databaseName, databaseBackupDirectory); } public static string PostEWS(string hostAddress, NetworkCredential networkCredential, string xml) { // Using spludlow HTTP client dont like !!!!!!!! //request.AllowWriteStreamBuffering = false; // Otherwise will hog memory in client EWS does not like !!!!!!!!!!!!! //request.SendChunked = true; string url = "https://" + hostAddress + "/EWS/Exchange.asmx"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Credentials = networkCredential; request.Method = "POST"; request.ContentType = "text/xml"; using (StreamWriter writer = new StreamWriter(request.GetRequestStream(), Encoding.UTF8)) writer.Write(xml); using (WebResponse response = request.GetResponse()) { using (Stream responseStream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8)) { return reader.ReadToEnd(); } } } //Spludlow.Net.Http.WebResponseInfo info = Spludlow.Net.Http.PostText(url, xml, "text/xml", null, networkCredential, null, null, Encoding.UTF8); //return info.Text; } public string UniqueFolderIdPrivateRoot() { return this.UniqueFolderId(WellKnownFolderName.Root); } public string UniqueFolderIdPublicRoot() { return this.UniqueFolderId(WellKnownFolderName.PublicFoldersRoot); } public string UniqueFolderId(WellKnownFolderName wellKnownFolderName) { Folder folder = Folder.Bind(this.ExchangeService, wellKnownFolderName, this.PropertySetIdOnly); return folder.Id.UniqueId; } public string MailBoxRootUniqueFolderId(string userEmailAddress) { Mailbox mailbox = new Mailbox(userEmailAddress); FolderId folderId = new FolderId(WellKnownFolderName.Root, mailbox); Folder folder = Folder.Bind(this.ExchangeService, folderId, this.PropertySetIdOnly); return folder.Id.UniqueId; } public void ExportItem2(string itemId, string filename, string host, string templateFilename, string exchangeVersion) { string template = File.ReadAllText(templateFilename, Encoding.UTF8); StringBuilder text = new StringBuilder(template); text.Replace("@ExchangeVersion", exchangeVersion); text.Replace("@ItemId", itemId); string xml = text.ToString(); File.WriteAllText(filename + ".send.xml.txt", xml); string result = PostEWS(host, this.NetworkCredential, xml); File.WriteAllText(filename + ".result.xml.txt", result); } public void ImportMessage(string filename, string targetFolderId, Spludlow.Exchange exchange) { //Spludlow.Email.CDOSYS.ReadMessage(filename); } public void ImportMessageOLD(string filename, string targetFolderId, Spludlow.Exchange exchange, string sourceItemId, string createNewFilename, string exchangeVersion, string postAddress) { EmailMessage sourceMessage = EmailMessage.Bind(exchange.ExchangeService, sourceItemId); byte[] data = File.ReadAllBytes(filename); string base64data = Convert.ToBase64String(data); StringBuilder clean = new StringBuilder(); using (StringReader reader = new StringReader(base64data)) { int lineSize = 55; char[] buffer = new char[lineSize]; int count; while ((count = reader.Read(buffer, 0, lineSize)) > 0) { clean.Append(buffer, 0, count); clean.AppendLine(); } } base64data = clean.ToString(); File.WriteAllBytes(filename + ".back.dat", Convert.FromBase64String(base64data)); File.WriteAllText(filename + ".txt", base64data); string template = File.ReadAllText(createNewFilename, Encoding.UTF8); StringBuilder text = new StringBuilder(template); text.Replace("@ExchangeVersion", exchangeVersion); text.Replace("@Id", targetFolderId); text.Replace("@ChangeKey", sourceMessage.Id.ChangeKey); text.Replace("@Data", ""); //base64data); string xml = text.ToString(); File.WriteAllText(filename + ".xml.txt", xml); string result = PostEWS(postAddress, this.NetworkCredential, xml); Spludlow.Log.Report("EWS", result); } public string CreateFolder(string parentFolderId, string name) { Folder folder = new Folder(this.ExchangeService); folder.DisplayName = name; folder.Save(new FolderId(parentFolderId)); return folder.Id.UniqueId; } public void CreateFolder(string folderPath) { int index = folderPath.LastIndexOf("/"); string parentFolder = folderPath.Substring(0, index); string folderName = folderPath.Substring(index + 1); // /Top of Information Store string rootFolderId = this.UniqueFolderId(WellKnownFolderName.Root); // Slow !!! DataTable table = this.QueryFolders(rootFolderId).Tables[0]; DataRow[] rows = table.Select("Path = '" + parentFolder + "'"); if (rows.Length > 1) throw new ApplicationException("Exchange, CreateFolder; Found multiple parent paths for: " + folderPath); if (rows.Length == 0) throw new ApplicationException("Exchange, CreateFolder; Did not find parent for: " + folderPath); string parentId = (string)rows[0]["UniqueId"]; Folder folder = new Folder(this.ExchangeService); folder.DisplayName = folderName; folder.Save(new FolderId(parentId)); } public void RenameFolder(string folderId, string name) { FolderId id = new FolderId(folderId); Folder folder = Folder.Bind(this.ExchangeService, id); folder.DisplayName = name; folder.Update(); } public void CreateItem(Spludlow.Email.SimpleMailMessage message, string targetFolderId) { EmailMessage exchangeMessage = new EmailMessage(this.ExchangeService); exchangeMessage.Subject = message.Subject; if (message.HTMLBody.Length > 0) exchangeMessage.Body = new MessageBody(BodyType.HTML, message.HTMLBody); else exchangeMessage.Body = new MessageBody(BodyType.Text, message.TextBody); if (message.FromAddress != null) { exchangeMessage.From = new EmailAddress(message.FromAddress[0][1], message.FromAddress[0][0]); } foreach (string[] toAddress in message.ToAddress) exchangeMessage.ToRecipients.Add(toAddress[1], toAddress[0]); foreach (string[] replyToAddress in message.ReplyToAddress) exchangeMessage.ReplyTo.Add(replyToAddress[1], replyToAddress[0]); foreach (string[] attachment in message.Attachments) { // // Attachments [0] = Store Filename, [1] Filename, [2] = MIME string tempFilename = attachment[0]; string filename = attachment[1]; string contentMediaType = attachment[2]; byte[] data = null; try { data = File.ReadAllBytes(tempFilename); } catch (IOException ee) { if ((uint)ee.HResult != 0x800700E1) throw ee; Spludlow.Log.Warning(tempFilename + ", " + filename, ee); } if (data == null) continue; FileAttachment exchangeAttachment = exchangeMessage.Attachments.AddFileAttachment(filename, data); exchangeAttachment.ContentType = contentMediaType; if (filename.StartsWith("cid:") == true) { exchangeAttachment.Name = filename.Substring(4); exchangeAttachment.IsInline = true; exchangeAttachment.ContentId = filename; } else { exchangeAttachment.Name = filename; } } if (message.ReceivedTime == DateTime.MinValue) message.ReceivedTime = message.SentOn; // PR_CLIENT_SUBMIT_TIME if (message.SentOn != DateTime.MinValue) exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(57, MapiPropertyType.SystemTime), message.SentOn.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); // PR_MESSAGE_DELIVERY_TIME if (message.ReceivedTime != DateTime.MinValue) exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(3590, MapiPropertyType.SystemTime), message.ReceivedTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); // #define PR_MESSAGE_FLAGS PROP_TAG( PT_LONG, 0x0E07) exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(3591, MapiPropertyType.Integer), "1"); // Not Draft exchangeMessage.Save(targetFolderId); } public static int[] MAPITagSysTimes() { string[] headerData = new string[] { "PR_DEFERRED_DELIVERY_TIME 0x000F", "PR_DELIVER_TIME 0x0010", "PR_EXPIRY_TIME 0x0015", "PR_LATEST_DELIVERY_TIME 0x0019", "PR_RECEIPT_TIME 0x002A", "PR_REPLY_TIME 0x0030", "PR_REPORT_TIME 0x0032", "PR_CLIENT_SUBMIT_TIME 0x0039", "PR_PROVIDER_SUBMIT_TIME 0x0048", "PR_ORIGINAL_SUBMIT_TIME 0x004E", "PR_ORIGINAL_DELIVERY_TIME 0x0055", "PR_START_DATE 0x0060", "PR_END_DATE 0x0061", "PR_MESSAGE_DELIVERY_TIME 0x0E06", "PR_CREATION_TIME 0x3007", "PR_LAST_MODIFICATION_TIME 0x3008", "PR_WEDDING_ANNIVERSARY 0x3A41", "PR_BIRTHDAY 0x3A42", }; List values = new List(); foreach (string line in headerData) { string[] parts = line.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries); values.Add(Int32.Parse(parts[1].Substring(2), System.Globalization.NumberStyles.HexNumber)); } return values.ToArray(); } private static Guid StickyNotePropertySetId = new Guid("0006200E-0000-0000-C000-000000000046"); private static ExtendedPropertyDefinition PropertyStickyNoteColour = new ExtendedPropertyDefinition(StickyNotePropertySetId, 0x8B00, MapiPropertyType.Integer); //#define olBlue 0 //#define olGreen 1 //#define olPink 2 //#define olYellow 3 //#define olWhite 4 public void CreateNote(string subject, string textBody, string targetFolderId) { EmailMessage exchangeMessage = new EmailMessage(this.ExchangeService); exchangeMessage.ItemClass = "IPM.StickyNote"; exchangeMessage.Subject = subject; exchangeMessage.Body = new MessageBody(BodyType.Text, textBody); ////exchangeMessage.DateTimeCreated; ////exchangeMessage.DateTimeReceived; ////exchangeMessage.DateTimeSent; ////// #define PR_CLIENT_SUBMIT_TIME PROP_TAG( PT_SYSTIME, 0x0039) ////exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(0x0039, MapiPropertyType.SystemTime), dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); ////// #define PR_MESSAGE_DELIVERY_TIME PROP_TAG( PT_SYSTIME, 0x0E06) ////exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(0x0E06, MapiPropertyType.SystemTime), dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); //foreach (int tagId in MAPITagSysTimes()) // exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(tagId, MapiPropertyType.SystemTime), dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); //// ////exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(3590, MapiPropertyType.SystemTime), dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")); // #define PR_MESSAGE_FLAGS PROP_TAG( PT_LONG, 0x0E07) //exchangeMessage.SetExtendedProperty(new ExtendedPropertyDefinition(0x0E07, MapiPropertyType.Integer), "1"); // Not Draft exchangeMessage.SetExtendedProperty(PropertyStickyNoteColour, 3); // Yellow exchangeMessage.Save(targetFolderId); } public void ExportCalendarFolder(string topFolderId, string exportDirectory, bool delete, bool hardDelete) { DataTable itemsTable = this.QueryCalendarFolder(topFolderId).Tables[0]; DataRow[] rows = itemsTable.Select("Keep = True"); if (rows.Length == 0) { Directory.Delete(exportDirectory, true); return; } foreach (DataRow itemRow in rows) { // "UniqueId DateTimeReceived Size Subject AppointmentType DateTimeCreated Start End Keep", string itemUniqueId = (string)itemRow["UniqueId"]; string subject = (string)itemRow["Subject"]; DateTime dateTimeReceived = (DateTime)itemRow["DateTimeReceived"]; string filename = exportDirectory + @"\" + Spludlow.Text.TimeStamp(dateTimeReceived) + "_" + subject.Trim(); this.ExportItem(itemUniqueId, filename); // will add extention !!!! .xml } } public void ImportCalendarFolder(string targetFolderId, string sourceDirectory) { CalendarFolder folder = CalendarFolder.Bind(this.ExchangeService, targetFolderId); foreach (string filename in Directory.GetFiles(sourceDirectory, "*.ics")) { Appointment appointment = new Appointment(this.ExchangeService); appointment.MimeContent = new MimeContent("UTF-8", File.ReadAllBytes(filename)); appointment.Save(folder.Id); } } public void TestCreateContact(string targetFolderId, string sendXmlFilename, string serverAddress) { string send = File.ReadAllText(sendXmlFilename, Encoding.UTF8); string result = PostEWS(serverAddress, this.NetworkCredential, send); Spludlow.Log.Report("XML Result", result); } public void ExportContactsFolder(string topFolderId, string exportDirectory, bool delete, bool hardDelete) { DataTable itemsTable = this.QueryContactsFolder(topFolderId).Tables[0]; foreach (DataRow itemRow in itemsTable.Rows) { // "UniqueId DateTimeReceived Size Subject", string itemUniqueId = (string)itemRow["UniqueId"]; string subject = (string)itemRow["Subject"]; DateTime dateTimeReceived = (DateTime)itemRow["DateTimeReceived"]; string filename = exportDirectory + @"\" + Spludlow.Text.TimeStamp(dateTimeReceived) + "_" + subject.Trim(); this.ExportItem(itemUniqueId, filename); // will add extention !!!! .xml } Spludlow.Log.Report("ExportContactsFolder", itemsTable); } public void ExportContacts(string folderId, string exportFilename) { // seems to break at 8192 int pageSize = 4096; int offset = 0; bool more = true; ContactsFolder folder = ContactsFolder.Bind(this.ExchangeService, folderId); int extentionIndex = exportFilename.LastIndexOf("."); while (more == true) { ItemView itemView = new ItemView(pageSize, offset * pageSize); itemView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties); this.ExchangeService.TraceEnabled = true; try { this.ExchangeTraceListener.Reset(); FindItemsResults items = folder.FindItems(itemView); string[] result = this.ExchangeTraceListener.Read(); if (result.Length != 1) throw new ApplicationException("Did not trace 1 result: " + result.Length); string pageFilename = exportFilename.Substring(0, extentionIndex) + "." + offset.ToString() + exportFilename.Substring(extentionIndex); if (items.TotalCount > 0) File.WriteAllText(pageFilename, result[0], Encoding.UTF8); more = items.MoreAvailable; ++offset; } finally { this.ExchangeService.TraceEnabled = false; } } } public void ExportContactsIndividual(string folderId, string directory, string exportFilename) { // seems to break at 8192 int pageSize = 4096; int offset = 0; bool more = true; ContactsFolder folder = ContactsFolder.Bind(this.ExchangeService, folderId); int extentionIndex = exportFilename.LastIndexOf("."); while (more == true) { ItemView itemView = new ItemView(pageSize, offset * pageSize); itemView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties); this.ExchangeService.TraceEnabled = true; try { this.ExchangeTraceListener.Reset(); FindItemsResults items = folder.FindItems(itemView); string[] result = this.ExchangeTraceListener.Read(); if (result.Length != 1) throw new ApplicationException("Did not trace 1 result: " + result.Length); string pageFilename = exportFilename.Substring(0, extentionIndex) + "." + offset.ToString() + exportFilename.Substring(extentionIndex); if (items.TotalCount > 0) File.WriteAllText(pageFilename, result[0], Encoding.UTF8); more = items.MoreAvailable; ++offset; } finally { this.ExchangeService.TraceEnabled = false; } } } public void ExportContacts2(string folderId, string directory) { // MIME conversion is not supported for this item type. contact.MimeContent.Content, ContactSchema.MimeContent Contact & Item ItemSchema.MimeContent // old verison of exchange DataTable table = this.QueryItems(folderId).Tables[0]; foreach (DataRow row in table.Rows) { string itemId = (string)row["UniqueId"]; Contact contact = Contact.Bind(this.ExchangeService, itemId); PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, ContactSchema.Body); //.FirstClassProperties, ItemSchema.Body); //propertySet.RequestedBodyType = BodyType.Text; contact.Load(propertySet); EmailMessage message = new EmailMessage(this.ExchangeService); ItemAttachment itemAttachment = message.Attachments.AddItemAttachment(); } } // Notes does not have own folder type // Task does !!! public void ExportItemsBatchXML(string folderId, string exportFilename) // change !!!! same as above ?? folder type { // seems to break at 8192 int pageSize = 4096; int offset = 0; bool more = true; Folder folder = Folder.Bind(this.ExchangeService, folderId); int extentionIndex = exportFilename.LastIndexOf("."); while (more == true) { ItemView itemView = new ItemView(pageSize, offset * pageSize); itemView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties); //, EmailMessageSchema.Body); itemView.PropertySet.RequestedBodyType = BodyType.Text; // note this.ExchangeService.TraceEnabled = true; try { this.ExchangeTraceListener.Reset(); FindItemsResults items = folder.FindItems(itemView); string[] result = this.ExchangeTraceListener.Read(); if (result.Length != 1) throw new ApplicationException("Did not trace 1 result: " + result.Length); string pageFilename = exportFilename.Substring(0, extentionIndex) + "." + offset.ToString() + exportFilename.Substring(extentionIndex); if (items.TotalCount > 0) File.WriteAllText(pageFilename, result[0], Encoding.UTF8); more = items.MoreAvailable; ++offset; } finally { this.ExchangeService.TraceEnabled = false; } } } public void ExportNotes(string folderId, string targetDirectory) { DataTable table = this.QueryItems(folderId).Tables[0]; if (table.Rows.Count == 0) { Directory.Delete(targetDirectory, true); return; } foreach (DataRow row in table.Rows) { string itemId = (string)row["UniqueId"]; Item item = Item.Bind(this.ExchangeService, itemId); PropertySet propertySet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Body); propertySet.RequestedBodyType = BodyType.Text; this.ExchangeService.TraceEnabled = true; try { this.ExchangeTraceListener.Reset(); item.Load(propertySet); string[] result = this.ExchangeTraceListener.Read(); if (result.Length != 1) throw new ApplicationException("Did not trace 1 result: " + result.Length); string subject = item.Subject; if (subject == null) subject = ""; string filename = targetDirectory + @"\" + Spludlow.Text.TimeStamp(item.DateTimeReceived) + "_" + Spludlow.Io.Paths.LegalFileName(subject) + ".xml"; if (item.ItemClass == "IPM.StickyNote") File.WriteAllText(filename, result[0], Encoding.UTF8); else Spludlow.Log.Warning("ExportNotes; ItemClass: " + item.ItemClass); } finally { this.ExchangeService.TraceEnabled = false; } } } public void ExportMessages(string topFolderId, string exportDirectory, DateTime beforeDate, bool delete, bool hardDelete) { DateTime startDate = DateTime.MinValue; this.ExportMessages(topFolderId, exportDirectory, startDate, beforeDate, delete, hardDelete); } public void ExportMessages(string topFolderId, string exportDirectory, DateTime startDate, DateTime beforeDate, bool delete, bool hardDelete) { DataTable table = this.QueryFolders(topFolderId).Tables[0]; foreach (DataRow row in table.Rows) { string folderType = (string)row["FolderType"]; if (folderType != "Folder") continue; int totalCount = (int)row["TotalCount"]; if (totalCount == 0) continue; string uniqueId = (string)row["UniqueId"]; DataTable itemsTable = this.QueryMessages(uniqueId, startDate, beforeDate).Tables[0]; if (itemsTable.Rows.Count == 0) continue; string path = (string)row["Path"]; path = exportDirectory + path.Replace("/", @"\"); Directory.CreateDirectory(path); foreach (DataRow itemRow in itemsTable.Rows) { string itemUniqueId = (string)itemRow["UniqueId"]; ItemId itemId = new ItemId(itemUniqueId); Item item = Item.Bind(this.ExchangeService, itemId); //, this.PropertySetMimeContent); item.Load(this.PropertySetMimeContent); string itemTypeName = item.GetType().Name; EmailAddress fromEmailAddress = null; if (itemTypeName == "EmailMessage") { EmailMessage emailMessage = (EmailMessage)item; fromEmailAddress = emailMessage.From; } if (itemTypeName == "PostItem") { PostItem postItem = (PostItem)item; fromEmailAddress = postItem.From; } int maxLength = 32; string subject = Spludlow.Io.Paths.LegalFileName((string)itemRow["Subject"]); if (subject.Length > maxLength) subject = subject.Substring(0, maxLength); DateTime dateTimeReceived = (DateTime)itemRow["DateTimeReceived"]; string smtpFromAddress = ""; if (fromEmailAddress != null && fromEmailAddress.Address != null) { NameResolutionCollection names = this.ExchangeService.ResolveName(fromEmailAddress.Address); if (names.Count > 0) smtpFromAddress = names[0].Mailbox.Address; else smtpFromAddress = fromEmailAddress.Name; } maxLength = 48; string fromAddress = Spludlow.Io.Paths.LegalFileName(smtpFromAddress); if (fromAddress.Length > maxLength) fromAddress = fromAddress.Substring(0, maxLength); string filename = Spludlow.Text.TimeStamp(dateTimeReceived) + "_" + subject + "_" + fromAddress + ".EML"; itemRow["Filename"] = filename; File.WriteAllBytes(path + @"\" + filename, item.MimeContent.Content); if (fromEmailAddress != null) { itemRow["FromDisplay"] = fromEmailAddress.Name; itemRow["FromAddress"] = fromEmailAddress.Address; } } // try finally the table string indexPath = path + @"\_Index.txt"; Spludlow.Data.TextTable.Write(indexPath, itemsTable, Encoding.UTF8); // Do Deletes in batches !!!!!! if (delete == true) { foreach (DataRow itemRow in itemsTable.Rows) { string itemUniqueId = (string)itemRow["UniqueId"]; ItemId itemId = new ItemId(itemUniqueId); Item item = Item.Bind(this.ExchangeService, itemId); if (hardDelete == true) item.Delete(DeleteMode.HardDelete); else item.Delete(DeleteMode.MoveToDeletedItems); } } } } public void DeleteItem(string itemId, bool hardDelete) { ItemId id = new ItemId(itemId); Item item = Item.Bind(this.ExchangeService, id); if (hardDelete == true) item.Delete(DeleteMode.HardDelete); else item.Delete(DeleteMode.MoveToDeletedItems); } public void ClearFolder(string folderId, bool hardDelete) { DataTable table = this.QueryItems(folderId).Tables[0]; foreach (DataRow row in table.Rows) { string itemId = (string)row["UniqueId"]; this.DeleteItem(itemId, hardDelete); } } private PropertySet PropertySetMimeContent = new PropertySet(ItemSchema.MimeContent, PostItemSchema.From, EmailMessageSchema.From); public static string[] ListWellKnownFolderNames() { return Enum.GetNames(typeof(WellKnownFolderName)); } public Dictionary WellKnownFolderNameIds(string userEmailAddress) { string[] names = new string[] { "Calendar", "Contacts", //"DeletedItems", "Drafts", "Inbox", //"Journal", "Notes", "Outbox", "SentItems", "Tasks", //"MsgFolderRoot", //"PublicFoldersRoot", //"Root", //"JunkEmail", //"SearchFolders", //"VoiceMail", //"RecoverableItemsRoot", //"RecoverableItemsDeletions", //"RecoverableItemsVersions", //"RecoverableItemsPurges", //"ArchiveRoot", //"ArchiveMsgFolderRoot", //"ArchiveDeletedItems", //"ArchiveRecoverableItemsRoot", //"ArchiveRecoverableItemsDeletions", //"ArchiveRecoverableItemsVersions", //"ArchiveRecoverableItemsPurges", //"SyncIssues", //"Conflicts", //"LocalFailures", //"ServerFailures", //"RecipientCache", Only valid on new servers older servers /Top of Information Store/Suggested Contacts //"QuickContacts", //"ConversationHistory", //"ToDoSearch", }; Dictionary result = new Dictionary(); Mailbox mailbox = new Mailbox(userEmailAddress); foreach (string name in names) { WellKnownFolderName wellKnownFolderName = (WellKnownFolderName)Enum.Parse(typeof(WellKnownFolderName), name); FolderId folderId = new FolderId(wellKnownFolderName, mailbox); Folder folder = Folder.Bind(this.ExchangeService, folderId, this.PropertySetIdOnly); result.Add(folder.Id.UniqueId, name); // ID, NAME !!! } return result; } //WellKnownFolderName.Calendar; // WellKnownFolderName.Contacts; // WellKnownFolderName.Drafts; // WellKnownFolderName.Inbox; // WellKnownFolderName.Notes; // WellKnownFolderName.Outbox; // WellKnownFolderName.RecipientCache; // WellKnownFolderName.SentItems; // WellKnownFolderName.Tasks; public DataSet QueryFolders(string topFolderId) { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "UniqueId DisplayName Depth Path FolderType ChildFolderCount TotalCount", // iswellknows !!! "String String Int32 String String Int32 Int32", }); this.WalkFolders(table, topFolderId, 0, null); DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); return dataSet; } public DataSet Test() { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "Info", "String", }); // Root string folderUniqueId = this.UniqueFolderId(WellKnownFolderName.Root); FolderId folderId = new FolderId(folderUniqueId); Folder folder = Folder.Bind(this.ExchangeService, folderId, new PropertySet(BasePropertySet.IdOnly)); PropertySet set = new PropertySet(FolderSchema.Id, FolderSchema.DisplayName, FolderSchema.ChildFolderCount, FolderSchema.TotalCount); folder.Load(set); table.Rows.Add(folderUniqueId); DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); return dataSet; } private void WalkFolders(DataTable table, string folderUniqueId, int depth, string path) { FolderId folderId = new FolderId(folderUniqueId); Folder folder; try { folder = Folder.Bind(this.ExchangeService, folderId, new PropertySet(BasePropertySet.IdOnly)); } catch (Exception ee) { Spludlow.Log.Warning("WalkFolders: " + folderUniqueId, ee); return; } PropertySet set = new PropertySet(FolderSchema.Id, FolderSchema.DisplayName, FolderSchema.ChildFolderCount, FolderSchema.TotalCount); folder.Load(set); string displayPath = ""; if (folder.DisplayName != null) displayPath = Spludlow.Io.Paths.LegalFileName(folder.DisplayName); if (depth == 0) { path = "/"; } else { if (depth == 1) path = "/" + displayPath; else path = path + "/" + displayPath; } table.Rows.Add(folder.Id.UniqueId, folder.DisplayName, depth, path, folder.GetType().Name, folder.ChildFolderCount, folder.TotalCount); //folder.ManagedFolderInformation FolderView view = new FolderView(Int32.MaxValue); FindFoldersResults results = folder.FindFolders(view); foreach (Folder subFolder in results.Folders) this.WalkFolders(table, subFolder.Id.UniqueId, depth + 1, path); } public DataSet QueryMessages(string folderUniqueId, DateTime startDate, DateTime beforeEndDate) { int pageSzie = Int32.MaxValue; int pageIndex = 0; FolderId folderId = new FolderId(folderUniqueId); Folder folder = Folder.Bind(this.ExchangeService, folderId); DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "UniqueId DateTimeReceived Size Subject ItemType FromDisplay FromAddress Filename", "String DateTime Int32 String String String String String", }); DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); ItemView itemView = new ItemView(pageSzie, pageIndex); itemView.PropertySet = new PropertySet(ItemSchema.DateTimeReceived, ItemSchema.Size, ItemSchema.Subject); // need to load for this will take too long here, EmailMessageSchema.From); // from for mail !!! SearchFilter.SearchFilterCollection searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And); if (startDate != DateTime.MinValue) searchFilter.Add(new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, startDate)); if (beforeEndDate != DateTime.MaxValue) searchFilter.Add(new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, beforeEndDate)); if (searchFilter.Count == 0) searchFilter = null; itemView.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending); itemView.OrderBy.Add(ItemSchema.Subject, SortDirection.Ascending); FindItemsResults findResults = folder.FindItems(searchFilter, itemView); foreach (Item item in findResults.Items) { string itemType = item.GetType().Name; if (itemType != "EmailMessage" && itemType != "PostItem") continue; string subject = item.Subject; if (subject == null) subject = ""; table.Rows.Add(item.Id.UniqueId, item.DateTimeReceived, item.Size, subject, itemType, null, null, null); } return dataSet; } public DataSet QueryItems(string folderUniqueId) { int pageSzie = Int32.MaxValue; int pageIndex = 0; FolderId folderId = new FolderId(folderUniqueId); Folder folder = Folder.Bind(this.ExchangeService, folderId); DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "UniqueId DateTimeReceived Size Subject ItemType FromDisplay FromAddress Filename", "String DateTime Int32 String String String String String", }); DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); ItemView itemView = new ItemView(pageSzie, pageIndex); itemView.PropertySet = new PropertySet(ItemSchema.DateTimeReceived, ItemSchema.Size, ItemSchema.Subject); // need to load for this will take too long here, EmailMessageSchema.From); // from for mail !!! SearchFilter.SearchFilterCollection searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And); //if (startDate != DateTime.MinValue) // searchFilter.Add(new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, startDate)); //if (beforeEndDate != DateTime.MaxValue) // searchFilter.Add(new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, beforeEndDate)); if (searchFilter.Count == 0) searchFilter = null; itemView.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending); itemView.OrderBy.Add(ItemSchema.Subject, SortDirection.Ascending); FindItemsResults findResults = folder.FindItems(searchFilter, itemView); foreach (Item item in findResults.Items) { string itemType = item.GetType().Name; //if (itemType != "EmailMessage" && itemType != "PostItem") // continue; string subject = item.Subject; if (subject == null) subject = ""; table.Rows.Add(item.Id.UniqueId, item.DateTimeReceived, item.Size, subject, itemType, null, null, null); } return dataSet; } public DataSet QueryCalendarFolder(string folderId) { DateTime startDate = new DateTime(2000, 1, 1); DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "UniqueId DateTimeReceived Size Subject AppointmentType DateTimeCreated Start End Keep", "String DateTime Int32 String String DateTime DateTime DateTime Boolean", }); // Note that recurring master calendar items aren't returned in a call to FindAppointments. If you want to retrieve recurring masters, or you want a more general approach to retrieving calendar items, you need to use ExchangeService.FindItems. CalendarFolder folder = CalendarFolder.Bind(this.ExchangeService, folderId); SearchFilter.SearchFilterCollection searchFilter = new SearchFilter.SearchFilterCollection(); searchFilter.Add(new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start, startDate)); ItemView itemView = new ItemView(Int32.MaxValue); itemView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties); FindItemsResults findResults = this.ExchangeService.FindItems(folder.Id, searchFilter, itemView); foreach (Appointment item in findResults.Items) { string subject = item.Subject; if (subject == null) subject = ""; bool keep = true; if (item.AppointmentType == AppointmentType.Single && item.End < DateTime.Now) keep = false; table.Rows.Add(item.Id.UniqueId, item.DateTimeReceived, item.Size, subject, item.AppointmentType.ToString(), item.DateTimeCreated, item.Start, item.End, keep); } DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); return dataSet; } public DataSet QueryContactsFolder(string folderId) { DataTable table = Spludlow.Data.TextTable.ReadText(new string[] { "UniqueId DateTimeReceived Size Subject", "String DateTime Int32 String", }); ContactsFolder folder = ContactsFolder.Bind(this.ExchangeService, folderId); ItemView itemView = new ItemView(Int32.MaxValue, 0); FindItemsResults items = folder.FindItems(itemView); foreach (Item item in items) { Contact contact = Contact.Bind(this.ExchangeService, item.Id, PropertySetFirstClassProperties); string subject = contact.Subject; if (subject == null) subject = ""; table.Rows.Add(contact.Id.UniqueId, contact.DateTimeReceived, contact.Size, subject); } DataSet dataSet = new DataSet(); dataSet.Tables.Add(table); return dataSet; } private PropertySet PropertySetIdOnly = new PropertySet(BasePropertySet.IdOnly); private PropertySet PropertySetFirstClassProperties = new PropertySet(BasePropertySet.FirstClassProperties); private PropertySet PropertySetAppointmentSchemaMimeContent = new PropertySet(AppointmentSchema.MimeContent); private PropertySet PropertySetContactSchemaSchemaMimeContent = new PropertySet(ContactSchema.MimeContent); public void ExportItem(string uniqueId, string filename) { Item item = Item.Bind(this.ExchangeService, uniqueId); string itemTypeName = item.GetType().Name; if (itemTypeName == "Appointment") { Appointment appointment = Appointment.Bind(this.ExchangeService, item.Id); appointment.Load(PropertySetAppointmentSchemaMimeContent); File.WriteAllBytes(filename + ".ics", appointment.MimeContent.Content); //appointment.LastOccurrence; return; } //if (itemTypeName == "Contact") //{ // Contact contact = Contact.Bind(this.ExchangeService, item.Id); //, PropertySetContactSchemaSchemaMimeContent); // contact.Load(PropertySetFirstClassProperties); // StringBuilder text = new StringBuilder(); // text.AppendLine(contact.Subject); // text.AppendLine(contact.DateTimeReceived.ToString()); // text.AppendLine(contact.FileAs); // text.AppendLine(contact.FileAsMapping.ToString()); // text.AppendLine(contact.DisplayName); // text.AppendLine(contact.GivenName); // text.AppendLine(contact.Initials); // text.AppendLine(contact.MiddleName); // text.AppendLine(contact.CompleteName.FullName); // text.AppendLine(contact.CompleteName.GivenName); // text.AppendLine(contact.CompleteName.Initials); // text.AppendLine(contact.CompleteName.MiddleName); // text.AppendLine(contact.CompleteName.NickName); // text.AppendLine(contact.CompleteName.Suffix); // text.AppendLine(contact.CompleteName.Surname); // text.AppendLine(contact.CompleteName.Title); // text.AppendLine(contact.CompleteName.YomiGivenName); // text.AppendLine(contact.CompleteName.YomiSurname); // text.AppendLine(contact.CompanyName); // File.WriteAllText(filename + ".txt", text.ToString(), Encoding.UTF8); // return; //} // contacts the vCard (.vcf) if (itemTypeName == "EmailMessage" || itemTypeName == "PostItem") { item.Load(this.PropertySetMimeContent); File.WriteAllBytes(filename + ".EML", item.MimeContent.Content); } else { //this.ExchangeService.TraceEnabled = true; this.EnableTrace(true, false); try { this.ExchangeTraceListener.Reset(); item.Load(this.PropertySetFirstClassProperties); string[] result = this.ExchangeTraceListener.Read(); if (result.Length != 1) throw new ApplicationException("Did not trace 1 result: " + result.Length); File.WriteAllText(filename + ".XML", result[0], Encoding.UTF8); } finally { //this.ExchangeService.TraceEnabled = false; this.DisableTrace(); } } } public void CopyItem(string uniqueId, string filename) { } public void MirrorFolder(string folderUniqueId, string directory, int historyDays) { if (Directory.Exists(directory) == false) Directory.CreateDirectory(directory); string indexFilename = directory + @"\_Index.txt"; DataTable table; if (File.Exists(indexFilename) == true) { table = Spludlow.Data.TextTable.ReadFile(indexFilename, Encoding.UTF8); } else { table = Spludlow.Data.TextTable.ReadText(new string[] { "UniqueId DateTimeReceived Size Subject DateTimeDownload Filename", "String* DateTime Int32 String String String", }); } DateTime startDate = DateTime.Now.AddMinutes(-historyDays); DataTable serverTable = QueryMessages(folderUniqueId, startDate, DateTime.MaxValue).Tables[0]; // Download new int downloadCount = 0; foreach (DataRow serverRow in serverTable.Rows) { string itemUniqueId = (string)serverRow["UniqueId"]; if (table.Rows.Find(itemUniqueId) != null) continue; ItemId itemId = new ItemId(itemUniqueId); Item item = Item.Bind(this.ExchangeService, itemId); item.Load(this.PropertySetMimeContent); DateTime dateTimeReceived = (DateTime)serverRow["DateTimeReceived"]; string subject = (string)serverRow["Subject"]; string filename = directory + @"\" + Spludlow.Io.Paths.LegalFileName(Spludlow.Text.TimeStamp(dateTimeReceived) + "_" + subject + ".EML"); filename = Spludlow.Io.Files.UniqueExistingName(filename); DataRow row = table.NewRow(); row["UniqueId"] = itemUniqueId; row["DateTimeReceived"] = dateTimeReceived; row["Size"] = (int)serverRow["Size"]; row["Subject"] = subject; row["DateTimeDownload"] = DateTime.Now; row["Filename"] = Path.GetFileName(filename); table.Rows.Add(row); File.WriteAllBytes(filename, item.MimeContent.Content); ++downloadCount; } // Delete old int deleteCount = 0; if (downloadCount > 0) // Only delete old when getting new? (errors above wont reach here anyway) { foreach (DataRow deleteRow in table.Select("DateTimeReceived < #" + Spludlow.Text.TimeStampDataTableSelect(startDate) + "#")) deleteRow.Delete(); List existingFilenames = new List(Directory.GetFiles(directory, "*.EML")); foreach (DataRow row in table.Rows) { string filename = directory + @"\" + (string)row["Filename"]; if (existingFilenames.Contains(filename) == true) existingFilenames.Remove(filename); } deleteCount = existingFilenames.Count; foreach (string filename in existingFilenames) File.Delete(filename); } if (File.Exists(indexFilename) == true) File.Delete(indexFilename); Spludlow.Data.TextTable.Write(indexFilename, table, Encoding.UTF8); Spludlow.Log.Report("Exchange MirrorFolder; New:" + downloadCount + ", Old:" + deleteCount, table); } private DataSet SearchFolderOLD(string uniqueId, string subject, DateTime receivedAfter, DateTime receivedBefore, int minSize) { DataSet dataSet = new DataSet(); DataTable table = new DataTable(); table.Columns.Add("UniqueId", typeof(string)); table.Columns.Add("From", typeof(string)); table.Columns.Add("Subject", typeof(string)); table.Columns.Add("DateTimeSent", typeof(DateTime)); table.Columns.Add("DateTimeReceived", typeof(DateTime)); table.Columns.Add("Size", typeof(int)); Microsoft.Exchange.WebServices.Data.ItemView itemView = new Microsoft.Exchange.WebServices.Data.ItemView(Int32.MaxValue); itemView.PropertySet = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Size); SearchFilter.SearchFilterCollection searchFilterCollection = new SearchFilter.SearchFilterCollection(LogicalOperator.And); if (subject != null) searchFilterCollection.Add(new SearchFilter.ContainsSubstring(ItemSchema.Subject, subject)); if (receivedAfter != DateTime.MinValue) searchFilterCollection.Add(new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.DateTimeReceived, receivedAfter)); if (receivedBefore != DateTime.MaxValue) searchFilterCollection.Add(new SearchFilter.IsLessThan(ItemSchema.DateTimeReceived, receivedBefore)); if (minSize != 0) searchFilterCollection.Add(new SearchFilter.IsGreaterThanOrEqualTo(ItemSchema.Size, minSize)); Microsoft.Exchange.WebServices.Data.FindItemsResults itemResults = null; if (uniqueId.Length < 32) { WellKnownFolderName folderName = (WellKnownFolderName)Enum.Parse(typeof(WellKnownFolderName), uniqueId); if (searchFilterCollection.Count == 0) itemResults = this.ExchangeService.FindItems(folderName, itemView); else itemResults = this.ExchangeService.FindItems(folderName, searchFilterCollection, itemView); } else { FolderId folderId = new FolderId(uniqueId); if (searchFilterCollection.Count == 0) itemResults = this.ExchangeService.FindItems(folderId, itemView); else itemResults = this.ExchangeService.FindItems(folderId, searchFilterCollection, itemView); } foreach (Microsoft.Exchange.WebServices.Data.Item item in itemResults) { if (item is Microsoft.Exchange.WebServices.Data.EmailMessage) { Microsoft.Exchange.WebServices.Data.EmailMessage emailMessage = (Microsoft.Exchange.WebServices.Data.EmailMessage)item; string fromName = ""; if (emailMessage.From != null) fromName = emailMessage.From.Name; table.Rows.Add(new object[] { emailMessage.Id.UniqueId, fromName, emailMessage.Subject, emailMessage.DateTimeSent, emailMessage.DateTimeReceived, emailMessage.Size }); } } dataSet.Tables.Add(table); return dataSet; } } }