Repository: Sicos1977/MsgKit Branch: master Commit: 30f8c1957a6f Files: 135 Total size: 1.6 MB Directory structure: gitextract_xbt61gzj/ ├── .gitattributes ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── MsgKit/ │ ├── Address.cs │ ├── Appointment.cs │ ├── Attachments.cs │ ├── Contact.cs │ ├── ContactAssistant.cs │ ├── ContactBusiness.cs │ ├── ContactCommon.cs │ ├── ContactCompanyMain.cs │ ├── ContactHome.cs │ ├── ContactOther.cs │ ├── ContactWork.cs │ ├── ContactYomi.cs │ ├── Converter.cs │ ├── Email.cs │ ├── Enums/ │ │ ├── AddressBookEntryIdType.cs │ │ ├── AddressType.cs │ │ ├── AppointmentState.cs │ │ ├── AttachmentFlags.cs │ │ ├── AttachmentType.cs │ │ ├── MapiAccess.cs │ │ ├── MapiObjectType.cs │ │ ├── MeetingType.cs │ │ ├── MessageClass.cs │ │ ├── MessageEditorFormat.cs │ │ ├── MessageFlags.cs │ │ ├── MessageFormat.cs │ │ ├── MessageIconIndex.cs │ │ ├── MessageImportance.cs │ │ ├── MessagePriority.cs │ │ ├── PostalAddressId.cs │ │ ├── PropertyFlags.cs │ │ ├── PropertyKind.cs │ │ ├── PropertyType.cs │ │ ├── RecipientFlags.cs │ │ ├── RecipientRowAddressType.cs │ │ ├── RecipientRowDisplayType.cs │ │ ├── RecipientType.cs │ │ ├── RecurrencePatternCalendarType.cs │ │ ├── RecurrencePatternFirstDOWDay.cs │ │ ├── RecurrencePatternFrequency.cs │ │ ├── RecurrencePatternPatternType.cs │ │ ├── RecurrencePatternRecurrenceRangeType.cs │ │ ├── StoreSupportMask.cs │ │ ├── TaskAcceptanceState.cs │ │ ├── TaskHistory.cs │ │ ├── TaskMode.cs │ │ ├── TaskMultipleRecipients .cs │ │ ├── TaskOwnership.cs │ │ ├── TaskState.cs │ │ └── TaskStatus.cs │ ├── Exceptions/ │ │ ├── MKAttachment.cs │ │ ├── MKAttachmentExists.cs │ │ ├── MKInvalidProperty.cs │ │ ├── MKMessageSaved.cs │ │ └── MKPropertyNotFound.cs │ ├── Helpers/ │ │ ├── Conversion.cs │ │ ├── Crc32Calculator.cs │ │ ├── EmailAddress.cs │ │ ├── Exception.cs │ │ ├── ExtensionMethods.cs │ │ ├── FileManager.cs │ │ ├── Mapi.cs │ │ ├── MimeType.cs │ │ ├── Stream.cs │ │ └── Strings.cs │ ├── Message.cs │ ├── Mime/ │ │ ├── Decode/ │ │ │ ├── Base64.cs │ │ │ ├── EncodedWord.cs │ │ │ ├── EncodingFinder.cs │ │ │ ├── QuotedPrintable.cs │ │ │ ├── Rfc2231Decoder.cs │ │ │ ├── Rfc2822DateTime.cs │ │ │ ├── SizeParser.cs │ │ │ └── Utility.cs │ │ └── Header/ │ │ ├── ContentTransferEncoding.cs │ │ ├── HeaderExtractor.cs │ │ ├── HeaderFieldParser.cs │ │ ├── MessageHeader.cs │ │ ├── Received.cs │ │ └── RfcMailAddress.cs │ ├── MsgKit.csproj │ ├── MsgKit.snk │ ├── MsgKit.xml │ ├── NamedPropertyMapping.cs │ ├── NamedPropertyTags.cs │ ├── PropertyTags.cs │ ├── Receiving.cs │ ├── ReceivingRepresenting.cs │ ├── Recipient.cs │ ├── Representing.cs │ ├── Rtf/ │ │ ├── Compressor.cs │ │ └── Encapsulator.cs │ ├── Sender.cs │ ├── Streams/ │ │ ├── AttachmentProperties.cs │ │ ├── EmbeddedMessageProperties.cs │ │ ├── EntryStream.cs │ │ ├── GuidStream.cs │ │ ├── NamedProperties.cs │ │ ├── RecipientProperties.cs │ │ ├── StringStream.cs │ │ └── TopLevelProperties.cs │ ├── Structures/ │ │ ├── AddressBookEntryId.cs │ │ ├── CLSID.cs │ │ ├── NamedProperty.cs │ │ ├── OneOffEntryId.cs │ │ ├── Properties.cs │ │ ├── Property.cs │ │ ├── RecipientRow.cs │ │ ├── RecurrencePattern.cs │ │ ├── ReportTag.cs │ │ └── UnsendableRecipients.cs │ ├── Task.cs │ ├── ThreadIndex.cs │ ├── TranslateTags.cs │ ├── app.config │ └── packages.config ├── MsgKit.sln ├── MsgKit.sln.DotSettings ├── MsgKitTestTool/ │ ├── EmailForm.Designer.cs │ ├── EmailForm.cs │ ├── EmailForm.resx │ ├── MsgKitTestTool.csproj │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── Tests.cs │ ├── app.config │ └── packages.config └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [Sicos1977] ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates .vs/ # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ x64/ build/ bld/ [Bb]in/ [Oo]bj/ # Roslyn cache directories *.ide/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* #NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c *_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_* .*crunch*.local.xml # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # 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 ## TODO: Comment the next line if you want to checkin your ## web deploy settings but do note that will include unencrypted ## passwords #*.pubxml # NuGet Packages Directory packages/* ## TODO: If the tool you use requires repositories.config ## uncomment the next line #!packages/repositories.config # Enable "build/" folder in the NuGet Packages folder since # NuGet packages use it for MSBuild targets. # This line needs to be after the ignore of the build folder # (and the packages folder if the line above has been uncommented) !packages/build/ # 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 node_modules/ # 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 *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # LightSwitch generated files GeneratedArtifacts/ _Pvt_Extensions/ ModelManifest.xml .vs/MsgKit/v15/sqlite3/storage.ide /.vs/MsgKit/v15/Server/sqlite3/storage.ide-wal /.vs/MsgKit/v15/Server/sqlite3/storage.ide-shm /.vs/MsgKit/v15/Server/sqlite3/storage.ide /.vs/MsgKit/v15/Server/sqlite3/db.lock /.vs/MsgKit/v15/sqlite3/db.lock /.vs/MsgKit/v15/sqlite3/storage.ide-shm /.vs/VSWorkspaceState.json /.vs/slnx.sqlite /.vs/ProjectSettings.json /.vs/MsgKit/v15/sqlite3/storage.ide-wal /.vs/MsgKit/v16/Server/sqlite3/db.lock ================================================ FILE: MsgKit/Address.cs ================================================ // // Address.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using MsgKit.Enums; using MsgKit.Structures; namespace MsgKit; /// /// A base class for , , /// and /// public class Address { #region Fields /// /// The messaging user's e-mail address type /// private AddressType _addressType; #endregion #region Properties /// /// The E-mail address /// public string Email { get; internal set; } /// /// The displayname for the /// public string DisplayName { get; internal set; } /// /// The original displayname for the /// public string OriginalDisplayName => AddressType == AddressType.Smtp ? Email : DisplayName; /// /// Returns the messaging user's e-mail address type. Use /// when this property returns /// public AddressType AddressType { get => _addressType; internal set { _addressType = value; switch (value) { case AddressType.Unknown: AddressTypeString = string.Empty; break; case AddressType.Ex: AddressTypeString = "EX"; break; case AddressType.Smtp: AddressTypeString = "SMTP"; break; case AddressType.Fax: AddressTypeString = "FAX"; break; case AddressType.Mhs: AddressTypeString = "MHS"; break; case AddressType.Profs: AddressTypeString = "PROFS"; break; case AddressType.X400: AddressTypeString = "X400"; break; default: throw new ArgumentOutOfRangeException(nameof(value), value, null); } } } /// /// Returns the as a string /// public string AddressTypeString { get; private set; } /// /// /// internal OneOffEntryId OneOffEntryId => new(Email, DisplayName, AddressType); #endregion #region Constructor /// /// Creates this object and sets all it's needed properties /// /// The full E-mail address /// The displayname for the /// The public Address(string email, string displayName, AddressType addressType = AddressType.Smtp) { Email = email ?? string.Empty; DisplayName = string.IsNullOrWhiteSpace(displayName) ? email : displayName; AddressType = addressType; } #endregion } ================================================ FILE: MsgKit/Appointment.cs ================================================ // // Appointment.cs // // Author: Kees van Spelde and Travis Semple // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using MsgKit.Enums; // ReSharper disable UnusedMember.Global namespace MsgKit; /// /// A class to make an appointment /// /// /// Inherits from >, because it has quite a few of the same fields /// public class Appointment : Email { #region Properties /// /// Holds the location for the Appointment /// public string Location { get; set; } /// /// This property specifies whether the event is an all-day event, as /// specified by the user. A value of true indicates that the event is an all-day /// event, in which case the start time and end time must be midnight so that the /// duration is a multiple of 24 hours and is at least 24 hours. A value of false /// or the absence of this property indicates the event is not an all-day event. The /// client or server must not infer the value as TRUE when a user happens to create an /// event that is 24 hours, even if the event starts and ends at midnight. /// public bool AllDay { get; set; } /// /// Holds meeting information for the appointment /// public DateTime MeetingStart { get; set; } /// /// The end of the meeting /// public DateTime MeetingEnd { get; set; } #endregion #region Constructors /// /// Sends an appointment with sender, representing, subject, draft. /// /// Contains sender name and email. /// Contains who this appointment is representing. /// Contains the subject for this appointment. /// Is this a draft? public Appointment(Sender sender, Representing representing, string subject, bool draft = false) : base(sender, representing, subject, draft) { } /// /// Used to send without the representing structure. /// /// /// /// public Appointment(Sender sender, string subject, bool draft = false) : base(sender, subject, draft) { } #endregion #region WriteToStorage /// /// Writes all the properties that are part of the object either as 's /// or 's to the /// private new void WriteToStorage() { Class = MessageClass.IPM_Appointment; NamedProperties.AddProperty(NamedPropertyTags.PidLidLocation, Location); NamedProperties.AddProperty(NamedPropertyTags.PidLidAppointmentStartWhole, MeetingStart); NamedProperties.AddProperty(NamedPropertyTags.PidLidAppointmentEndWhole, MeetingEnd); NamedProperties.AddProperty(NamedPropertyTags.PidLidMeetingType, MeetingType.mtgRequest); NamedProperties.AddProperty(NamedPropertyTags.PidLidAppointmentSubType, AllDay); NamedProperties.AddProperty(NamedPropertyTags.PidLidAppointmentStateFlags, AppointmentState.asfMeeting); } #endregion #region Save /// /// Saves the message to the given /// /// public new void Save(Stream stream) { WriteToStorage(); base.Save(stream); } /// /// Saves the message to the given /// /// public new void Save(string fileName) { WriteToStorage(); base.Save(fileName); } #endregion } ================================================ FILE: MsgKit/Attachments.cs ================================================ // // Attachments.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.Collections.Generic; using System.IO; using System.Linq; using MsgKit.Enums; using MsgKit.Exceptions; using MsgKit.Helpers; using MsgKit.Streams; using MsgKit.Structures; using OpenMcdf; using Stream = System.IO.Stream; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedMember.Global namespace MsgKit; /// /// Contains a list of objects that are added to a /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc842285.aspx /// public class Attachments : List { #region CheckAttachmentFileName /// /// Checks if the already exists in this object /// /// /// // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local private void CheckAttachmentFileName(string fileName, string contentId) { var file = Path.GetFileName(fileName); if (this.Any( attachment => attachment.FileName.Equals(fileName, StringComparison.InvariantCultureIgnoreCase) && string.Equals(attachment.ContentId, contentId, StringComparison.InvariantCultureIgnoreCase))) throw new MKAttachmentExists($"The attachment with the name '{file}' already exists"); } #endregion #region WriteToStorage /// /// Writes the objects to the given /// and it will set all the needed properties /// /// The root /// /// Total size of the written objects and it's /// internal long WriteToStorage(Storage rootStorage) { long size = 0; for (var index = 0; index < Count; index++) { var attachment = this[index]; var storage = rootStorage.CreateStorage(PropertyTags.AttachmentStoragePrefix + index.ToString("X8").ToUpper()); size += attachment.WriteProperties(storage, index); } return size; } #endregion #region AddAttachment /// /// Adds an by (default) /// /// The file to add with its full path /// Indicates how an attachment should be displayed in a rich text message /// Set to true to add the attachment inline /// The id for the inline attachment when is set to true /// Raised when the could not be found /// Raised when an attachment with the same name already exists /// /// Raised when is set to true and /// is null, white space or empty /// public void Add(string fileName, long renderingPosition = -1, bool isInline = false, string contentId = "") { if (Count >= 2048) throw new MKAttachment("To many attachments, an msg file can have a maximum of 2048 attachment"); CheckAttachmentFileName(fileName, contentId); var file = new FileInfo(fileName); var stream = file.OpenRead(); Add(new Attachment(stream, file.Name, file.CreationTime, file.LastWriteTime, AttachmentType.ATTACH_BY_VALUE, renderingPosition, isInline, contentId)); } /// /// Adds an stream by (default) /// /// The stream to the attachment /// The name for the attachment /// Indicates how an attachment should be displayed in a rich text message /// Set to true to add the attachment inline /// The id for the inline attachment when is set to true /// Raised when the stream is null /// Raised when an attachment with the same name already exists /// /// Raised when is set to true and /// is null, white space or empty /// public void Add(Stream stream, string fileName, long renderingPosition = -1, bool isInline = false, string contentId = "") { if (Count >= 2048) throw new MKAttachment("To many attachments, an msg file can have a maximum of 2048 attachment"); if (stream == null) throw new ArgumentNullException(nameof(stream)); CheckAttachmentFileName(fileName, contentId); var dateTime = DateTime.Now; Add(new Attachment(stream, fileName, dateTime, dateTime, AttachmentType.ATTACH_BY_VALUE, renderingPosition, isInline, contentId)); } /// /// Adds an stream by (default) /// /// The stream to the attachment /// The name for the attachment /// Raised when the stream is null /// Raised when an attachment with the same name already exists internal void AddContactPhoto(Stream stream, string fileName) { if (stream == null) throw new ArgumentNullException(nameof(stream)); var dateTime = DateTime.Now; Add(new Attachment(stream, fileName, dateTime, dateTime, AttachmentType.ATTACH_BY_VALUE, -1, false, string.Empty, true)); } #endregion #region AddLink /// /// Adds an by as a link /// /// The /// Indicates how an attachment should be displayed in a rich text message /// Set to true to add the attachment inline /// The id for the inline attachment when is set to true /// Raised when the could not be found /// Raised when an attachment with the same name already exists /// /// Raised when is set to true and /// is null, white space or empty /// /// /// Universal naming convention (UNC) names are recommended for fully-qualified paths, which should be used with /// . /// public void AddLink(FileInfo file, long renderingPosition = -1, bool isInline = false, string contentId = "") { CheckAttachmentFileName(file.Name, contentId); Add(new Attachment( file, AttachmentType.ATTACH_BY_REF_ONLY, renderingPosition, isInline, contentId)); } #endregion } /// /// This class represents an attachment /// public class Attachment { #region Fields private readonly FileInfo _file; #endregion #region Properties /// /// The stream to the attachment /// public Stream Stream { get; } /// /// The filename of the attachment /// public string FileName { get; } /// /// The /// public AttachmentType Type { get; } /// /// Indicates how an attachment should be displayed in a rich text message. It can be set to an /// offset in characters, with the first character of the message content as stored in the /// (PidTagBody) property being offset 0, or to -1 (0xFFFFFFFF), indicating that the attachment should /// not be rendered within the message text at all. /// public long RenderingPosition { get; } /// /// True when the attachment is inline /// public bool IsInline { get; } /// /// The content id for an inline attachment /// public string ContentId { get; } /// /// Returns true when the attachment is a contact photo /// /// /// Only valid when the message is a contact card, otherwise always false /// public bool IsContactPhoto { get; } /// /// The date and time when the attachment was created /// public DateTime CreationTime { get; } /// /// The date and time when the attachment was last modified /// public DateTime LastModificationTime { get; } #endregion #region Constructor /// /// Creates a new attachment object and sets all its properties /// /// The stream to the attachment /// The attachment filename with its full path /// The date and time when the attachment was created /// The date and time when the attachment was last modified /// The /// Indicates how an attachment should be displayed in a rich text message /// True when the attachment is inline /// The id for the attachment when is set to true /// Set to true when the attachment is a contact photo /// /// Raised when is set to true and /// is null, white space or empty /// internal Attachment(Stream stream, string fileName, DateTime creationTime, DateTime lastModificationTime, AttachmentType type = AttachmentType.ATTACH_BY_VALUE, long renderingPosition = -1, bool isInline = false, string contentId = "", bool isContactPhoto = false) { Stream = stream; FileName = Path.GetFileName(fileName); CreationTime = creationTime; LastModificationTime = lastModificationTime; Type = type; RenderingPosition = renderingPosition; IsInline = isInline; ContentId = contentId; IsContactPhoto = isContactPhoto; if (isInline && string.IsNullOrWhiteSpace(contentId)) throw new ArgumentNullException(nameof(contentId), "The content id cannot be empty when isInline is set to true"); } /// /// Creates a new attachment object and sets all its properties /// /// The /// The /// Indicates how an attachment should be displayed in a rich text message /// True when the attachment is inline /// The id for the attachment when is set to true /// Set to true when the attachment is a contact photo /// /// Raised when is set to true and /// is null, white space or empty /// internal Attachment(FileInfo file, AttachmentType type = AttachmentType.ATTACH_BY_VALUE, long renderingPosition = -1, bool isInline = false, string contentId = "", bool isContactPhoto = false) { _file = file; Stream = file.OpenRead(); FileName = file.Name; CreationTime = file.CreationTime; LastModificationTime = file.LastWriteTime; Type = type; RenderingPosition = renderingPosition; IsInline = isInline; ContentId = contentId; IsContactPhoto = isContactPhoto; if (isInline && string.IsNullOrWhiteSpace(contentId)) throw new ArgumentNullException(nameof(contentId), "The content id cannot be empty when isInline is set to true"); } #endregion #region GetShortFileName /// /// This method will convert a long filename to a short dos 8.3 one /// /// The long filename /// private static string GetShortFileName(string fileName) { var name = Path.GetFileNameWithoutExtension(fileName); var extension = Path.GetExtension(fileName); if (name != null) name = (name.Length > 8 ? name.Substring(0, 6) + "~1" : name).ToUpperInvariant(); if (extension != null) name += "." + (extension.Length > 3 ? extension.Substring(1, 3) : extension.TrimStart('.')) .ToUpperInvariant(); return name; } #endregion #region WriteProperties /// /// Writes all the string and binary properties as a to the /// given /// /// The /// The index /// /// Total size of the written object and it's /// internal long WriteProperties(Storage storage, int index) { var propertiesStream = new AttachmentProperties(); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_NUM, index, PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey(), PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_RECORD_KEY, Mapi.GenerateRecordKey(), PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_RENDERING_POSITION, RenderingPosition, PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_OBJECT_TYPE, MapiObjectType.MAPI_ATTACH); if (IsContactPhoto) propertiesStream.AddProperty(PropertyTags.PR_ATTACHMENT_CONTACTPHOTO, true, PropertyFlags.PROPATTR_READABLE); if (!string.IsNullOrEmpty(FileName)) { propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_NAME_W, FileName); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_FILENAME_W, GetShortFileName(FileName)); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_LONG_FILENAME_W, FileName); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_EXTENSION_W, Path.GetExtension(FileName)); if (!string.IsNullOrEmpty(ContentId)) propertiesStream.AddProperty(PropertyTags.PR_ATTACH_CONTENT_ID_W, ContentId); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_MIME_TAG_W, MimeTypes.GetMimeType(FileName)); } propertiesStream.AddProperty(PropertyTags.PR_ATTACH_METHOD, Type); switch (Type) { case AttachmentType.ATTACH_BY_VALUE: case AttachmentType.ATTACH_EMBEDDED_MSG: propertiesStream.AddProperty(PropertyTags.PR_ATTACH_DATA_BIN, Stream.ToByteArray()); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_SIZE, Stream.Length); break; case AttachmentType.ATTACH_BY_REF_ONLY: propertiesStream.AddProperty(PropertyTags.PR_ATTACH_DATA_BIN, Array.Empty()); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_SIZE, _file.Length); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_LONG_PATHNAME_W, _file.FullName); break; //case AttachmentType.ATTACH_EMBEDDED_MSG: // var msgStorage = storage.AddStorage(PropertyTags.PR_ATTACH_DATA_BIN.Name); // var cf = new CompoundFile(Stream); // Storage.Copy(cf.RootStorage, msgStorage); // propertiesStream.AddProperty(PropertyTags.PR_ATTACH_SIZE, Stream.Length); // propertiesStream.AddProperty(PropertyTags.PR_ATTACH_ENCODING, 0); // break; case AttachmentType.ATTACH_BY_REFERENCE: case AttachmentType.ATTACH_BY_REF_RESOLVE: case AttachmentType.NO_ATTACHMENT: case AttachmentType.ATTACH_OLE: throw new NotSupportedException("AttachByReference, AttachByRefResolve, NoAttachment and AttachOle are not supported"); } if (IsInline) { propertiesStream.AddProperty(PropertyTags.PR_ATTACHMENT_HIDDEN, true); propertiesStream.AddProperty(PropertyTags.PR_ATTACH_FLAGS, AttachmentFlags.ATT_MHTML_REF); } var utcNow = DateTime.UtcNow; propertiesStream.AddProperty(PropertyTags.PR_CREATION_TIME, utcNow); propertiesStream.AddProperty(PropertyTags.PR_LAST_MODIFICATION_TIME, utcNow); propertiesStream.AddProperty(PropertyTags.PR_STORE_SUPPORT_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE); return propertiesStream.WriteProperties(storage); } #endregion } ================================================ FILE: MsgKit/Contact.cs ================================================ // // Contact.cs // // Author: Kees van Spelde and Travis Semple // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.Collections.Generic; using System.IO; using System.Linq; using MsgKit.Enums; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// A class used to make a new Outlook contact MSG file /// public class Contact : Email { #region Properties /// /// The contact image, this needs to be an JPG file /// public byte[] ContactPicture { get; set; } /// /// File the contact card as ... /// public string FileUnder { get; set; } /// /// The instant messaging address /// public string InstantMessagingAddress { get; set; } /// /// Indicates whether the end-user wants this message object hidden from other users who have access to the message object /// public bool Private { get; set; } /// /// The birthday /// public DateTime? BirthDay { get; set; } /// /// Specifies the wedding anniversary /// public DateTime? WeddingAnniversary { get; set; } /// /// Information about the assistant /// public ContactAssistant Assistant { get; set; } /// /// Contains a telephone number that the message recipient can use to reach the sender /// public string CallBackTelePhoneNumber { get; set; } /// /// Contains the recipient's car telephone number /// public string CarTelePhoneNumber { get; set; } /// /// The names of the childrens /// public List ChildrensNames { get; set; } /// /// The company's main info /// public ContactCompanyMain CompanyMain { get; set; } /// /// The department name /// public string DepartmentName { get; set; } /// /// Contains a generational abbreviation that follows the full name of the recipient /// public string Generation { get; set; } /// /// Contains the first or given name of the recipient /// public string GivenName { get; set; } /// /// Contains the initials for parts of the full name of the recipient /// public string Initials { get; set; } /// /// Contains the recipient's ISDN-capable telephone number /// // ReSharper disable once InconsistentNaming public string ISDNNumber { get; set; } /// /// Contains a value that indicates the language in which the messaging user is writing messages /// public string Language { get; set; } /// /// Contains the location of the recipient in a format that is useful to the recipient's organization. /// public string Location { get; set; } /// /// Contains the name of the recipient's manager /// public string ManagerName { get; set; } /// /// Contains the middle name of a contact /// public string MiddleName { get; set; } /// /// Contains the recipient's cellular telephone number /// public string MobileTelephoneNumber { get; set; } /// /// Contains the nickname of the contact /// public string NickName { get; set; } /// /// Contains the recipient's office location /// public string OfficeLocation { get; set; } /// /// Contains the recipient's office location /// public string OfficeTelephoneNumber { get; set; } /// /// Contains the URL of a user's personal home page /// public string PersonalHomePage { get; set; } /// /// Contains the recipient's postal address /// public string PostalAddress { get; set; } /// /// Contains the telephone number of the recipient's primary fax machine /// public string PrimaryFaxNumber { get; set; } /// /// Contains the recipient's primary telephone number /// public string PrimaryTelephoneNumber { get; set; } /// /// Contains the profession of the user /// public string Profession { get; set; } /// /// Contains the recipient's radio telephone number /// public string RadioTelephoneNumber { get; set; } /// /// Contains the user's spouse name /// public string SpouseName { get; set; } /// /// Contains the last or surname of the recipient /// public string SurName { get; set; } /// /// Contains the recipient's telex number /// public string TelexNumber { get; set; } /// /// Contains the recipient's job title /// public string Title { get; set; } /// /// Contains the telephone number for the contact's text telephone (TTY) or telecommunication device for the deaf (TDD) /// // ReSharper disable once InconsistentNaming public string TTYTDDPhoneNumber { get; set; } /// /// Contains the recipient's pager telephone number /// public string PagerTelephoneNumber { get; set; } /// /// E-mail address 1 /// public Address Email1 { get; set; } /// /// E-mail address 2 /// public Address Email2 { get; set; } /// /// E-mail address 3 /// public Address Email3 { get; set; } ///// ///// Fax 1 ///// //public string Fax1 { get; set; } ///// ///// Fax 2 ///// //public string Fax2 { get; set; } ///// ///// Fax 3 ///// //public string Fax3 { get; set; } /// /// Yomi name and Yomi company name are fields for entering the phonetic equivalent for Japanese names. /// In Japan, there is commonly a Furigana equivalent for the Kanji name that is used for sorting and searching. /// public ContactYomi Yomi { get; set; } /// /// The work details /// public ContactWork Work { get; set; } /// /// The business details /// public ContactBusiness Business { get; set; } /// /// The home details /// public ContactHome Home { get; set; } /// /// The other address /// public ContactOther Other { get; set; } /// /// Specifies which physical address is the contact's mailing address /// public PostalAddressId PostalAddressId { get; set; } #endregion #region Constructors /// /// Creates this object and sets all the needed properties /// /// The of the E-mail /// The sender of the E-mail /// The subject of the E-mail /// Set to true to save the E-mail as a draft message /// Set to true to request a read receipt for the E-mail public Contact( Sender sender, Representing representing, string subject, bool draft = false, bool readReceipt = false) : base(sender, representing, subject, draft, readReceipt) { } /// /// Creates this object and sets all the needed properties /// /// The of the E-mail /// The subject of the E-mail /// Set to true to save the E-mail as a draft message /// Set to true to request a read receipt for the E-mail public Contact( Sender sender, string subject, bool draft = false, bool readReceipt = false) : base(sender, subject, draft, readReceipt) { } #endregion #region WriteToStorage /// /// Writes all the properties that are part of the object either as 's /// or 's to the /// private new void WriteToStorage() { Class = MessageClass.IPM_Contact; if (ContactPicture != null) { var memoryStream = new MemoryStream(ContactPicture); Attachments.AddContactPhoto(memoryStream, "ContactPicture.jpg"); NamedProperties.AddProperty(NamedPropertyTags.PidLidHasPicture, true); NamedProperties.AddProperty(NamedPropertyTags.PidLidSmartNoAttach, true); } else NamedProperties.AddProperty(NamedPropertyTags.PidLidHasPicture, false); if (!string.IsNullOrWhiteSpace(FileUnder)) NamedProperties.AddProperty(NamedPropertyTags.PidLidFileUnder, FileUnder); if (!string.IsNullOrWhiteSpace(InstantMessagingAddress)) NamedProperties.AddProperty(NamedPropertyTags.PidLidInstantMessagingAddress, InstantMessagingAddress); NamedProperties.AddProperty(NamedPropertyTags.PidLidPrivate, Private); if (BirthDay.HasValue) { NamedProperties.AddProperty(NamedPropertyTags.PidLidBirthdayLocal, BirthDay); TopLevelProperties.AddProperty(PropertyTags.PR_BIRTHDAY, BirthDay); } if (WeddingAnniversary.HasValue) { NamedProperties.AddProperty(NamedPropertyTags.PidLidWeddingAnniversaryLocal, WeddingAnniversary); TopLevelProperties.AddProperty(PropertyTags.PR_WEDDING_ANNIVERSARY, WeddingAnniversary); } if (Assistant != null) { if (!string.IsNullOrWhiteSpace(Assistant.Name)) TopLevelProperties.AddProperty(PropertyTags.PR_ASSISTANT_W, Assistant.Name); if (!string.IsNullOrWhiteSpace(Assistant.TelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_ASSISTANT_TELEPHONE_NUMBER_W, Assistant.TelephoneNumber); } if (!string.IsNullOrWhiteSpace(CallBackTelePhoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_CALLBACK_TELEPHONE_NUMBER_W, CallBackTelePhoneNumber); if (!string.IsNullOrWhiteSpace(CarTelePhoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_CAR_TELEPHONE_NUMBER_W, CarTelePhoneNumber); if (ChildrensNames != null) TopLevelProperties.AddProperty(PropertyTags.PR_CHILDRENS_NAMES_W, string.Join(", ", ChildrensNames)); if (CompanyMain != null) { if (!string.IsNullOrWhiteSpace(CompanyMain.Name)) TopLevelProperties.AddProperty(PropertyTags.PR_COMPANY_NAME_W, CompanyMain.Name); if (!string.IsNullOrWhiteSpace(CompanyMain.TelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_COMPANY_MAIN_PHONE_NUMBER_W, CompanyMain.TelephoneNumber); } if (!string.IsNullOrWhiteSpace(DepartmentName)) TopLevelProperties.AddProperty(PropertyTags.PR_DEPARTMENT_NAME_W, DepartmentName); if (!string.IsNullOrWhiteSpace(Generation)) TopLevelProperties.AddProperty(PropertyTags.PR_GENERATION_W, Generation); if (!string.IsNullOrWhiteSpace(GivenName)) TopLevelProperties.AddProperty(PropertyTags.PR_GIVEN_NAME_W, GivenName); if (!string.IsNullOrWhiteSpace(Initials)) TopLevelProperties.AddProperty(PropertyTags.PR_INITIALS_W, Initials); if (!string.IsNullOrWhiteSpace(ISDNNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_ISDN_NUMBER_W, ISDNNumber); if (!string.IsNullOrWhiteSpace(Language)) TopLevelProperties.AddProperty(PropertyTags.PR_LANGUAGE_W, Language); if (!string.IsNullOrWhiteSpace(Location)) TopLevelProperties.AddProperty(PropertyTags.PR_LOCATION_W, Location); if (!string.IsNullOrWhiteSpace(ManagerName)) TopLevelProperties.AddProperty(PropertyTags.PR_MANAGER_NAME_W, ManagerName); if (!string.IsNullOrWhiteSpace(MiddleName)) TopLevelProperties.AddProperty(PropertyTags.PR_MIDDLE_NAME_W, MiddleName); if (!string.IsNullOrWhiteSpace(MobileTelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_MOBILE_TELEPHONE_NUMBER_W, MobileTelephoneNumber); if (!string.IsNullOrWhiteSpace(NickName)) TopLevelProperties.AddProperty(PropertyTags.PR_NICKNAME_W, NickName); if (!string.IsNullOrWhiteSpace(OfficeLocation)) TopLevelProperties.AddProperty(PropertyTags.PR_OFFICE_LOCATION_W, OfficeLocation); if (!string.IsNullOrWhiteSpace(OfficeTelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS2_TELEPHONE_NUMBER_W, OfficeTelephoneNumber); if (!string.IsNullOrWhiteSpace(PersonalHomePage)) TopLevelProperties.AddProperty(PropertyTags.PR_PERSONAL_HOME_PAGE_W, PersonalHomePage); if (!string.IsNullOrWhiteSpace(PostalAddress)) TopLevelProperties.AddProperty(PropertyTags.PR_POSTAL_ADDRESS_W, PostalAddress); var addressBookProviderEmailList = new List(); if (!string.IsNullOrWhiteSpace(PrimaryFaxNumber)) { TopLevelProperties.AddProperty(PropertyTags.PR_PRIMARY_FAX_NUMBER_W, PrimaryFaxNumber); addressBookProviderEmailList.Add(5); } if (!string.IsNullOrWhiteSpace(PrimaryTelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_PRIMARY_TELEPHONE_NUMBER_W, PrimaryTelephoneNumber); if (!string.IsNullOrWhiteSpace(Profession)) TopLevelProperties.AddProperty(PropertyTags.PR_PROFESSION_W, Profession); if (!string.IsNullOrWhiteSpace(RadioTelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_RADIO_TELEPHONE_NUMBER_W, RadioTelephoneNumber); if (!string.IsNullOrWhiteSpace(SpouseName)) TopLevelProperties.AddProperty(PropertyTags.PR_SPOUSE_NAME_W, SpouseName); if (!string.IsNullOrWhiteSpace(SurName)) TopLevelProperties.AddProperty(PropertyTags.PR_SURNAME_W, SurName); if (!string.IsNullOrWhiteSpace(TelexNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_TELEX_NUMBER_W, TelexNumber); if (!string.IsNullOrWhiteSpace(Title)) TopLevelProperties.AddProperty(PropertyTags.PR_TITLE_W, Title); if (!string.IsNullOrWhiteSpace(TTYTDDPhoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_TTYTDD_PHONE_NUMBER_W, TTYTDDPhoneNumber); if (!string.IsNullOrWhiteSpace(PagerTelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_PAGER_TELEPHONE_NUMBER_W, PagerTelephoneNumber); var emailList = new List(); if (Email1 != null) { emailList.Add(NamedPropertyTags.PidLidEmail1DisplayName.Id); addressBookProviderEmailList.Add(0); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail1EmailAddress, Email1.Email); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail1DisplayName, Email1.DisplayName); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail1OriginalDisplayName, Email1.OriginalDisplayName); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail1AddressType, Email1.AddressTypeString); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail1OriginalEntryId, Email1.OneOffEntryId.ToByteArray()); } if (Email2 != null) { emailList.Add(NamedPropertyTags.PidLidEmail2DisplayName.Id); addressBookProviderEmailList.Add(1); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail2EmailAddress, Email2.Email); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail2DisplayName, Email2.DisplayName); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail2OriginalDisplayName, Email2.OriginalDisplayName); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail2AddressType, Email2.AddressTypeString); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail2OriginalEntryId, Email2.OneOffEntryId.ToByteArray()); } if (Email3 != null) { emailList.Add(NamedPropertyTags.PidLidEmail3DisplayName.Id); addressBookProviderEmailList.Add(2); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail3EmailAddress, Email3.Email); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail3DisplayName, Email3.DisplayName); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail3OriginalDisplayName, Email3.OriginalDisplayName); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail3AddressType, Email3.AddressTypeString); NamedProperties.AddProperty(NamedPropertyTags.PidLidEmail3OriginalEntryId, Email3.OneOffEntryId.ToByteArray()); } if (emailList.Any()) NamedProperties.AddProperty(NamedPropertyTags.PidLidEmailList, emailList.ToArray()); //if (!string.IsNullOrWhiteSpace(Fax1)) //{ // var fax1 = new Address(Fax1, SubjectNormalized, AddressType.Fax); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax1EmailAddress, fax1.Email); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax1OriginalDisplayName, fax1.OriginalDisplayName); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax1AddressType, fax1.AddressTypeString); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax1OriginalEntryId, fax1.OneOffEntryId.ToByteArray()); //} //if (!string.IsNullOrWhiteSpace(Fax2)) //{ // var fax2 = new Address(Fax2, SubjectNormalized, AddressType.Fax); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax2EmailAddress, fax2.Email); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax2OriginalDisplayName, fax2.OriginalDisplayName); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax2AddressType, fax2.AddressTypeString); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax2OriginalEntryId, fax2.OneOffEntryId.ToByteArray()); //} //if (!string.IsNullOrWhiteSpace(Fax3)) //{ // var fax3 = new Address(Fax3, SubjectNormalized, AddressType.Fax); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax3EmailAddress, fax3.Email); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax3OriginalDisplayName, fax3.OriginalDisplayName); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax3AddressType, fax3.AddressTypeString); // NamedProperties.AddProperty(NamedPropertyTags.PidLidFax3OriginalEntryId, fax3.OneOffEntryId.ToByteArray()); //} if (Yomi != null) { if (!string.IsNullOrWhiteSpace(Yomi.FirstName)) NamedProperties.AddProperty(NamedPropertyTags.PidLidYomiFirstName, Yomi.FirstName); if (!string.IsNullOrWhiteSpace(Yomi.LastName)) NamedProperties.AddProperty(NamedPropertyTags.PidLidYomiLastName, Yomi.LastName); if (!string.IsNullOrWhiteSpace(Yomi.CompanyName)) NamedProperties.AddProperty(NamedPropertyTags.PidLidYomiCompanyName, Yomi.CompanyName); } if (Work != null) { if (!string.IsNullOrWhiteSpace(Work.Address)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddress, Work.Address); if (!string.IsNullOrWhiteSpace(Work.Street)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddressStreet, Work.Street); if (!string.IsNullOrWhiteSpace(Work.PostalCode)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddressPostalCode, Work.PostalCode); if (!string.IsNullOrWhiteSpace(Work.PostOfficeBox)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddressPostOfficeBox, Work.PostOfficeBox); if (!string.IsNullOrWhiteSpace(Work.City)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddressCity, Work.City); if (!string.IsNullOrWhiteSpace(Work.Country)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddressCountry, Work.Country); if (!string.IsNullOrWhiteSpace(Work.CountryCode)) NamedProperties.AddProperty(NamedPropertyTags.PidLidWorkAddressCountryCode, Work.CountryCode); } if (Business != null) { if (!string.IsNullOrWhiteSpace(Business.Street)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_ADDRESS_STREET_W, Business.Street); if (!string.IsNullOrWhiteSpace(Business.City)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_ADDRESS_CITY_W, Business.City); if (!string.IsNullOrWhiteSpace(Business.Country)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_ADDRESS_COUNTRY_W, Business.Country); if (!string.IsNullOrWhiteSpace(Business.PostalCode)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_ADDRESS_POSTAL_CODE_W, Business.PostalCode); if (!string.IsNullOrWhiteSpace(Business.State)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W, Business.State); if (!string.IsNullOrWhiteSpace(Business.HomePage)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_HOME_PAGE_W, Business.HomePage); if (!string.IsNullOrWhiteSpace(Business.TelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_TELEPHONE_NUMBER_W, Business.TelephoneNumber); if (!string.IsNullOrWhiteSpace(Business.FaxNumber)) { TopLevelProperties.AddProperty(PropertyTags.PR_BUSINESS_FAX_NUMBER_W, Business.FaxNumber); addressBookProviderEmailList.Add(3); } } if (Home != null) { if (!string.IsNullOrWhiteSpace(Home.Address)) NamedProperties.AddProperty(NamedPropertyTags.PidLidHomeAddress, Home.Address); if (!string.IsNullOrWhiteSpace(Home.Street)) TopLevelProperties.AddProperty(PropertyTags.PR_HOME_ADDRESS_STREET_W, Home.Street); if (!string.IsNullOrWhiteSpace(Home.PostalCode)) TopLevelProperties.AddProperty(PropertyTags.PR_HOME_ADDRESS_POSTAL_CODE_W, Home.PostalCode); if (!string.IsNullOrWhiteSpace(Home.City)) TopLevelProperties.AddProperty(PropertyTags.PR_HOME_ADDRESS_CITY_W, Home.City); if (!string.IsNullOrWhiteSpace(Home.Country)) TopLevelProperties.AddProperty(PropertyTags.PR_HOME_ADDRESS_COUNTRY_W, Home.Country); if (!string.IsNullOrWhiteSpace(Home.TelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_HOME_TELEPHONE_NUMBER_W, Home.TelephoneNumber); if (!string.IsNullOrWhiteSpace(Home.TelephoneNumber2)) TopLevelProperties.AddProperty(PropertyTags.PR_HOME2_TELEPHONE_NUMBER_W, Home.TelephoneNumber2); if (!string.IsNullOrWhiteSpace(Home.FaxNumber)) { TopLevelProperties.AddProperty(PropertyTags.PR_HOME_FAX_NUMBER_W, Home.FaxNumber); addressBookProviderEmailList.Add(4); } } if (addressBookProviderEmailList.Any()) NamedProperties.AddProperty(NamedPropertyTags.PidLidAddressBookProviderEmailList, addressBookProviderEmailList.OrderBy(m => m).ToArray()); if (Other != null) { if (!string.IsNullOrWhiteSpace(Other.Address)) NamedProperties.AddProperty(NamedPropertyTags.PidLidOtherAddress, Other.Address); if (!string.IsNullOrWhiteSpace(Other.Street)) TopLevelProperties.AddProperty(PropertyTags.PR_OTHER_ADDRESS_STREET_W, Other.Street); if (!string.IsNullOrWhiteSpace(Other.PostalCode)) TopLevelProperties.AddProperty(PropertyTags.PR_OTHER_ADDRESS_POSTAL_CODE_W, Other.PostalCode); if (!string.IsNullOrWhiteSpace(Other.City)) TopLevelProperties.AddProperty(PropertyTags.PR_OTHER_ADDRESS_CITY_W, Other.City); if (!string.IsNullOrWhiteSpace(Other.Country)) TopLevelProperties.AddProperty(PropertyTags.PR_OTHER_ADDRESS_COUNTRY_W, Other.Country); if (!string.IsNullOrWhiteSpace(Other.State)) TopLevelProperties.AddProperty(PropertyTags.PR_OTHER_ADDRESS_STATE_OR_PROVINCE_W, Other.State); if (!string.IsNullOrWhiteSpace(Other.TelephoneNumber)) TopLevelProperties.AddProperty(PropertyTags.PR_OTHER_TELEPHONE_NUMBER_W, Other.TelephoneNumber); } } #endregion #region Save /// /// Saves the message to the given /// /// public new void Save(Stream stream) { WriteToStorage(); base.Save(stream); } /// /// Saves the message to the given /// /// public new void Save(string fileName) { WriteToStorage(); base.Save(fileName); } #endregion } ================================================ FILE: MsgKit/ContactAssistant.cs ================================================ // // ContactAssistant.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a assistent /// public class ContactAssistant { #region Properties /// /// The name of the assistant /// public string Name { get; set; } /// /// The telephone number of the assistant /// public string TelephoneNumber { get; set; } #endregion } ================================================ FILE: MsgKit/ContactBusiness.cs ================================================ // // ContactBusiness.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a business /// public class ContactBusiness : ContactOther { #region Properties /// /// The home-page /// public string HomePage { get; set; } /// /// The fax number /// public string FaxNumber { get; set; } #endregion } ================================================ FILE: MsgKit/ContactCommon.cs ================================================ // // ContactCommon.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// A placeholder for the , and common properties /// public class ContactCommon { #region Properties /// /// The street for the address /// public string Street { get; set; } /// /// The country for the address /// public string Country { get; set; } /// /// The postal code for the address /// public string PostalCode { get; set; } /// /// The city for the address /// public string City { get; set; } /// /// The telephone number /// public string TelephoneNumber { get; set; } #endregion } ================================================ FILE: MsgKit/ContactCompanyMain.cs ================================================ // // ContactAssistant.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a company main info /// public class ContactCompanyMain : ContactAssistant { } ================================================ FILE: MsgKit/ContactHome.cs ================================================ // // ContactHome.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a work address /// public class ContactHome : ContactOther { #region Properties /// /// The way the home address is displayed in the contact card
/// Some Street
/// Zip code Place
/// Some land
///
public new string Address { get; set; } /// /// The fax number /// public string FaxNumber { get; set; } /// /// The telephone 2 number /// public string TelephoneNumber2 { get; set; } #endregion } ================================================ FILE: MsgKit/ContactOther.cs ================================================ // // ContactOther.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a other address /// public class ContactOther : ContactCommon { #region Properties /// /// The way the home address is displayed in the contact card
/// Some Street
/// Zip code Place
/// Some land
///
public string Address { get; set; } /// /// The state for the address /// public string State { get; set; } #endregion } ================================================ FILE: MsgKit/ContactWork.cs ================================================ // // ContactWork.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a work address /// public class ContactWork : ContactCommon { #region Properties /// /// The way the work address is displayed in the contact card
/// Some Street
/// Zip code Place
/// Some land
///
public string Address { get; set; } /// /// The post office box for the address /// public string PostOfficeBox { get; set; } /// /// The country code for the address /// public string CountryCode { get; set; } #endregion } ================================================ FILE: MsgKit/ContactYomi.cs ================================================ // // ContactYomi.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// Placeholder for a other address /// public class ContactYomi { #region Properties /// /// The first name /// public string FirstName { get; set; } /// /// The last name /// public string LastName { get; set; } /// /// The company name /// public string CompanyName { get; set; } #endregion } ================================================ FILE: MsgKit/Converter.cs ================================================ // // Converter.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using System.Linq; using System.Text; using MimeKit; using MsgKit.Exceptions; using MsgKit.Helpers; using MsgKit.Streams; using OpenMcdf; // ReSharper disable UnusedMember.Global namespace MsgKit; /// /// This class exposes some methods to convert MSG to EML and vice versa /// public static class Converter { #region ConvertEmlToMsg /// /// Converts an EML file to MSG format /// /// The EML (MIME) file /// The MSG file public static void ConvertEmlToMsg(string emlFileName, string msgFileName) { using var emlFile = new FileStream(emlFileName, FileMode.Open); using var msgFile = new FileStream(msgFileName, FileMode.CreateNew); ConvertEmlToMsg(emlFile, msgFile); } /// /// Converts an EML file to MSG format /// /// The EML (MIME) input stream /// The MSG file output stream public static void ConvertEmlToMsg(Stream emlFile, Stream msgFile) { var eml = MimeMessage.Load(emlFile); var sender = new Sender(string.Empty, string.Empty); if (eml.From.Count > 0) { var mailAddress = (MailboxAddress)eml.From[0]; sender = new Sender(mailAddress.Address, mailAddress.Name); } var representing = new Representing(string.Empty, string.Empty); if (eml.ResentSender != null) representing = new Representing(eml.ResentSender.Address, eml.ResentSender.Name); else if (eml.From.Count > 0) { var mailAddress = (MailboxAddress)eml.From[0]; representing = new Representing(mailAddress.Address, mailAddress.Name); } var msg = new Email(sender, representing, eml.Subject) { InternetMessageId = eml.MessageId }; if(eml.Date.UtcDateTime > DateTime.MinValue) { msg.SentOn = eml.Date.UtcDateTime; msg.ReceivedOn = eml.Date.UtcDateTime; } using (var memoryStream = new MemoryStream()) { eml.Headers.WriteTo(memoryStream); msg.TransportMessageHeadersText = Encoding.ASCII.GetString(memoryStream.ToArray()); } msg.Priority = eml.Priority switch { MessagePriority.NonUrgent => Enums.MessagePriority.PRIO_NONURGENT, MessagePriority.Normal => Enums.MessagePriority.PRIO_NORMAL, MessagePriority.Urgent => Enums.MessagePriority.PRIO_URGENT, _ => msg.Priority }; msg.Importance = eml.Importance switch { MessageImportance.Low => Enums.MessageImportance.IMPORTANCE_LOW, MessageImportance.Normal => Enums.MessageImportance.IMPORTANCE_NORMAL, MessageImportance.High => Enums.MessageImportance.IMPORTANCE_HIGH, _ => msg.Importance }; foreach (var to in eml.To) { if (to is not MailboxAddress mailAddress) continue; msg.Recipients.AddTo(mailAddress.Address, mailAddress.Name); } foreach (var cc in eml.Cc) { var mailAddress = (MailboxAddress)cc; msg.Recipients.AddCc(mailAddress.Address, mailAddress.Name); } foreach (var bcc in eml.Bcc) { var mailAddress = (MailboxAddress)bcc; msg.Recipients.AddBcc(mailAddress.Address, mailAddress.Name); } using (var headerStream = new MemoryStream()) { eml.Headers.WriteTo(headerStream); headerStream.Position = 0; msg.TransportMessageHeadersText = Encoding.ASCII.GetString(headerStream.ToArray()); } var namelessCount = 0; var index = 1; // This loops through the top-level parts (i.e. it doesn't open up attachments and continue to traverse). // As such, any included messages are just attachments here. foreach (var bodyPart in eml.BodyParts) { var handled = false; // The first text/plain part (that's not an attachment) is the body part. if (!bodyPart.IsAttachment && bodyPart is TextPart text) { // Sets the first matching inline content type for body parts. if (msg.BodyText == null && text.IsPlain) { msg.BodyText = text.Text; handled = true; } if (msg.BodyHtml == null && text.IsHtml) { msg.BodyHtml = text.Text; handled = true; } if (msg.BodyRtf == null && text.IsRichText) { msg.BodyRtf = text.Text; handled = true; } } // If the part hasn't previously been handled by "body" part handling if (handled) continue; var attachmentStream = new MemoryStream(); var fileName = bodyPart.ContentType.Name; var extension = string.Empty; switch (bodyPart) { case MessagePart messagePart: { messagePart.Message.WriteTo(attachmentStream); if (messagePart.Message != null) fileName = messagePart.Message.Subject; extension = ".eml"; break; } case MessageDispositionNotification notification: fileName = notification.FileName; break; case MessageDeliveryStatus status: fileName = "details"; extension = ".txt"; status.WriteTo(FormatOptions.Default, attachmentStream, true); break; default: { var part = (MimePart)bodyPart; part.Content?.DecodeTo(attachmentStream); fileName = part.FileName; break; } } fileName = string.IsNullOrWhiteSpace(fileName) ? $"part_{++namelessCount:00}" : FileManager.RemoveInvalidFileNameChars(fileName); if (!string.IsNullOrEmpty(extension)) fileName += extension; var inline = bodyPart.ContentDisposition != null && !string.IsNullOrEmpty(bodyPart.ContentId) && bodyPart.ContentDisposition.Disposition.Equals("inline", StringComparison.InvariantCultureIgnoreCase); attachmentStream.Position = 0; try { msg.Attachments.Add(attachmentStream, fileName, -1, inline, bodyPart.ContentId); } catch (MKAttachmentExists) { var tempFileName = Path.GetFileNameWithoutExtension(fileName); var tempExtension = Path.GetExtension(fileName); msg.Attachments.Add(attachmentStream, $"{tempFileName}({index}){tempExtension}", -1, inline, bodyPart.ContentId); index += 1; } } msg.Save(msgFile); } #endregion #region ConvertMsgToEml /// /// Converts an MSG file to EML format /// /// The MSG file /// The EML (MIME) file public static void ConvertMsgToEml(string msgFileName, string emlFileName) { using var msgFile = new FileStream(msgFileName, FileMode.Open, FileAccess.Read); using var emlFile = new FileStream(emlFileName, FileMode.CreateNew); ConvertMsgToEml(msgFile, emlFile); } /// /// Converts an MSG file to EML format /// /// The MSG file input stream /// The EML (MIME) output stream public static void ConvertMsgToEml(Stream msgFile, Stream emlFile) { using var rootStorage = RootStorage.Open(msgFile, StorageModeFlags.LeaveOpen); // Read top-level properties var propsStream = rootStorage.OpenStream(PropertyTags.PropertiesStreamName); var topLevelProps = new TopLevelProperties(propsStream); // Read variable-size properties from substg streams var subject = ReadUnicodeString(rootStorage, PropertyTags.PR_SUBJECT_W); var bodyText = ReadUnicodeString(rootStorage, PropertyTags.PR_BODY_W); var htmlBytes = ReadBinaryProperty(rootStorage, PropertyTags.PR_HTML); var senderName = ReadUnicodeString(rootStorage, PropertyTags.PR_SENDER_NAME_W); var senderEmail = ReadUnicodeString(rootStorage, PropertyTags.PR_SENDER_EMAIL_ADDRESS_W); var senderSmtp = ReadUnicodeString(rootStorage, PropertyTags.PR_SMTP_ADDRESS_W); var messageId = ReadUnicodeString(rootStorage, PropertyTags.PR_INTERNET_MESSAGE_ID_W); // Determine sender SMTP address (prefer SMTP over email, discard Exchange DNs) var senderAddress = senderSmtp ?? senderEmail ?? string.Empty; if (senderAddress.StartsWith("/O=", StringComparison.OrdinalIgnoreCase)) senderAddress = string.Empty; // Read fixed properties var clientSubmitTime = topLevelProps.FirstOrDefault(p => p.Id == PropertyTags.PR_CLIENT_SUBMIT_TIME.Id); var importance = topLevelProps.FirstOrDefault(p => p.Id == PropertyTags.PR_IMPORTANCE.Id); var priority = topLevelProps.FirstOrDefault(p => p.Id == PropertyTags.PR_PRIORITY.Id); // Build MimeMessage var message = new MimeMessage(); if (!string.IsNullOrEmpty(senderAddress)) message.From.Add(new MailboxAddress(senderName ?? string.Empty, senderAddress)); if (!string.IsNullOrEmpty(subject)) message.Subject = subject; if (!string.IsNullOrEmpty(messageId)) message.MessageId = messageId; if (clientSubmitTime != null) message.Date = new DateTimeOffset(clientSubmitTime.ToDateTime); if (importance != null) { message.Importance = importance.ToInt switch { 0 => MessageImportance.Low, 2 => MessageImportance.High, _ => MessageImportance.Normal }; } if (priority != null) { message.Priority = priority.ToInt switch { -1 => MessagePriority.NonUrgent, 1 => MessagePriority.Urgent, _ => MessagePriority.Normal }; } // Read recipients for (var i = 0; i < topLevelProps.RecipientCount; i++) { var storageName = PropertyTags.RecipientStoragePrefix + i.ToString("X8"); if (!rootStorage.TryOpenStorage(storageName, out var recipStorage)) continue; var recipPropsStream = recipStorage.OpenStream(PropertyTags.PropertiesStreamName); var recipProps = new RecipientProperties(recipPropsStream); var displayName = ReadUnicodeString(recipStorage, PropertyTags.PR_DISPLAY_NAME_W); var emailAddress = ReadUnicodeString(recipStorage, PropertyTags.PR_EMAIL_ADDRESS_W); var smtpAddress = ReadUnicodeString(recipStorage, PropertyTags.PR_SMTP_ADDRESS_W); var address = smtpAddress ?? emailAddress ?? string.Empty; if (address.StartsWith("/O=", StringComparison.OrdinalIgnoreCase)) address = string.Empty; if (string.IsNullOrEmpty(address)) continue; var recipientType = recipProps.FirstOrDefault(p => p.Id == PropertyTags.PR_RECIPIENT_TYPE.Id); var type = recipientType?.ToInt ?? 1; var mailbox = new MailboxAddress(displayName ?? string.Empty, address); switch (type) { case 1: message.To.Add(mailbox); break; case 2: message.Cc.Add(mailbox); break; case 3: message.Bcc.Add(mailbox); break; } } // Build body and read attachments var builder = new BodyBuilder(); builder.TextBody = bodyText; if (htmlBytes != null) builder.HtmlBody = Encoding.UTF8.GetString(htmlBytes); for (var i = 0; i < topLevelProps.AttachmentCount; i++) { var storageName = PropertyTags.AttachmentStoragePrefix + i.ToString("X8"); if (!rootStorage.TryOpenStorage(storageName, out var attachStorage)) continue; var fileName = ReadUnicodeString(attachStorage, PropertyTags.PR_ATTACH_LONG_FILENAME_W) ?? ReadUnicodeString(attachStorage, PropertyTags.PR_ATTACH_FILENAME_W); var mimeTag = ReadUnicodeString(attachStorage, PropertyTags.PR_ATTACH_MIME_TAG_W); var contentId = ReadUnicodeString(attachStorage, PropertyTags.PR_ATTACH_CONTENT_ID_W); var attachData = ReadBinaryProperty(attachStorage, PropertyTags.PR_ATTACH_DATA_BIN); if (attachData == null) continue; var contentType = !string.IsNullOrEmpty(mimeTag) ? ContentType.Parse(mimeTag) : new ContentType("application", "octet-stream"); if (!string.IsNullOrEmpty(contentId)) { var attachment = builder.LinkedResources.Add(fileName ?? "inline", attachData, contentType); attachment.ContentId = contentId; } else { builder.Attachments.Add(fileName ?? "attachment", attachData, contentType); } } message.Body = builder.ToMessageBody(); message.WriteTo(emlFile); } #endregion #region ReadUnicodeString /// /// Reads a unicode string property from a substg stream in the given storage /// private static string ReadUnicodeString(Storage storage, PropertyTags.PropertyTag tag) { if (!storage.TryOpenStream(tag.Name, out var stream)) return null; using (stream) using (var reader = new BinaryReader(stream)) { var bytes = reader.ReadBytes((int)stream.Length); return Encoding.Unicode.GetString(bytes).TrimEnd('\0'); } } #endregion #region ReadBinaryProperty /// /// Reads a binary property from a substg stream in the given storage /// private static byte[] ReadBinaryProperty(Storage storage, PropertyTags.PropertyTag tag) { if (!storage.TryOpenStream(tag.Name, out var stream)) return null; using (stream) using (var reader = new BinaryReader(stream)) { return reader.ReadBytes((int)stream.Length); } } #endregion } ================================================ FILE: MsgKit/Email.cs ================================================ // // Email.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using MsgKit.Enums; using MsgKit.Helpers; using MsgKit.Mime.Header; using MsgKit.Rtf; using MsgKit.Structures; using OpenMcdf; using MessageImportance = MsgKit.Enums.MessageImportance; using MessagePriority = MsgKit.Enums.MessagePriority; using Stream = System.IO.Stream; // ReSharper disable GrammarMistakeInComment // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global namespace MsgKit; /// /// A class used to make a new Outlook E-mail MSG file /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc979231.aspx /// public class Email : Message, IDisposable { #region Fields /// /// The to find the prefix in a subject /// private static readonly Regex SubjectPrefixRegex = new(@"^(\D{1,3}:\s)(.*)$"); /// /// The E-mail /// private Recipients _recipients; /// /// The E-mail /// private Recipients _replyToRecipients; /// /// The E-mail /// private Attachments _attachments; /// /// The subject of the E-mail /// private string _subject; /// /// When set to <c>true</c> then the <see cref="Attachment.Stream"/>'s /// will not be disposed when calling the <see cref="Dispose"/> method. Default set to <c>false</c> /// private readonly bool _leaveAttachmentStreamsOpen; #endregion #region Properties /// /// Returns the sender of the E-mail from the /// public Sender Sender { get; } /// /// Contains the e-mail address for the messaging user represented by the . /// /// /// These properties are examples of the address properties for the messaging user who is being represented by the /// user. They must be set by the incoming transport provider, which is also responsible for /// authorization or verification of the delegate. If no messaging user is being represented, these properties should /// be set to the e-mail address contained in the PR_RECEIVED_BY_EMAIL_ADDRESS (PidTagReceivedByEmailAddress) property. /// public Representing Representing { get; } /// /// Returns the E-mail /// public Recipients Recipients => _recipients ??= new Recipients(); /// /// Returns the E-mail /// public Recipients ReplyToRecipients => _replyToRecipients ??= new Recipients(); /// /// Contains the e-mail address for the messaging user who receives the message. /// /// /// These properties are examples of the address properties for the messaging user who receives the message. They must /// be set by the incoming transport provider. /// public Receiving Receiving { get; set; } /// /// Contains the e-mail address for the messaging user who is represented by the user. /// /// /// These properties are examples of the address properties for the messaging user who is being represented by the /// user. They must be set by the incoming transport provider, which is also responsible for /// authorization or verification of the delegate. If no messaging user is being represented, these properties should /// be set to the e-mail address contained in the PR_RECEIVED_BY_EMAIL_ADDRESS (PidTagReceivedByEmailAddress) property. /// public ReceivingRepresenting ReceivingRepresenting { get; internal set; } /// /// Returns the subject prefix of the E-mail /// public string SubjectPrefix { get; private set; } /// /// Returns or sets the subject of the E-mail /// public string Subject { get => _subject; set { _subject = value; SetSubject(); } } /// /// Returns the normalized subject of the E-mail /// public string SubjectNormalized { get; private set; } /// /// Returns or sets the /// public MessagePriority Priority { get; set; } /// /// Returns or sets the /// public MessageImportance Importance { get; set; } /// /// Returns or sets the text body of the E-mail /// public string BodyText { get; set; } /// /// Returns or sets the html body of the E-mail /// public string BodyHtml { get; set; } /// /// The compressed RTF body part /// /// /// When not set then the RTF is generated from (when this property is set) /// public string BodyRtf { get; set; } /// /// Returns or set to true when is compressed /// public bool BodyRtfCompressed { get; set; } /// /// The E-mail /// public Attachments Attachments => _attachments ??= new Attachments(); /// /// Returns or sets the UTC date and time the has submitted the /// /// /// /// This property has to be set to UTC datetime. When not set then the current date /// and time is used /// public DateTime? SentOn { get; set; } /// /// Returns the UTC date and time when the was received /// /// /// This property has to be set to UTC datetime /// public DateTime? ReceivedOn { get; set; } /// /// Returns or sets the Internet Message Id /// /// /// Corresponds to the message ID field as specified in [RFC2822].

/// If set then this value will be used, when not set the value will be read from the /// when this property is set ///
public string InternetMessageId { get; set; } /// /// Returns or set the value of a Multipurpose Internet Mail Extensions (MIME) message's References header field /// /// /// If set then this value will be used, when not set the value will be read from the /// when this property is set /// public string InternetReferences { get; set; } /// /// Returns or sets the original message's PR_INTERNET_MESSAGE_ID (PidTagInternetMessageId) property value /// /// /// If set then this value will be used, when not set the value will be read from the /// when this property is set /// public string InReplyToId { get; set; } /// /// Sets or returns the property as a string (text). /// This property expects the headers as a string /// public string TransportMessageHeadersText { set => TransportMessageHeaders = HeaderExtractor.GetHeaders(value); get => TransportMessageHeaders != null ? TransportMessageHeaders.ToString() : string.Empty; } /// /// Returns or sets the transport message headers. These are only present when /// the message has been sent outside an Exchange environment to another mailserver /// null will be returned when not present /// /// /// Use the property if you want to set /// the headers directly from a string otherwise see the example code below. /// /// /// /// var email = new Email(); /// email.TransportMessageHeaders = new MessageHeader(); /// // ... do something with it, for example /// email.TransportMessageHeaders.SetHeaderValue("X-MY-CUSTOM-HEADER", "EXAMPLE VALUE"); /// /// public MessageHeader TransportMessageHeaders { get; set; } /// /// Returns true when the message is set as a draft message /// public bool Draft { get; } /// /// Returns true when a read receipt is requested /// public bool ReadRecipient { get; } /// /// Specifies the format for an editor to use to display a message. /// public MessageEditorFormat MessageEditorFormat { get; set; } #endregion #region Constructor /// /// Creates this object and sets all the needed properties /// /// The of the E-mail /// The subject of the E-mail /// Set to true to save the E-mail as a draft message /// Set to true to request a read receipt for the E-mail /// When set to true then the 's /// will not be disposed when calling the method. Default set to false public Email(Sender sender, string subject, bool draft = false, bool readReceipt = false, bool leaveAttachmentStreamsOpen = false) { Sender = sender; Subject = subject; Importance = MessageImportance.IMPORTANCE_NORMAL; IconIndex = MessageIconIndex.NewMail; Draft = draft; ReadRecipient = readReceipt; _leaveAttachmentStreamsOpen = leaveAttachmentStreamsOpen; } /// /// Creates this object and sets all the needed properties /// /// The of the E-mail /// The sender of the E-mail /// The subject of the E-mail /// Set to true to save the E-mail as a draft message /// Set to true to request a read receipt for the E-mail /// When set to true then the 's /// will not be disposed when calling the method. Default set to false public Email(Sender sender, Representing representing, string subject, bool draft = false, bool readReceipt = false, bool leaveAttachmentStreamsOpen = false) { Sender = sender; Representing = representing; Subject = subject; Importance = MessageImportance.IMPORTANCE_NORMAL; IconIndex = MessageIconIndex.NewMail; Draft = draft; ReadRecipient = readReceipt; _leaveAttachmentStreamsOpen = leaveAttachmentStreamsOpen; } #endregion #region SetSubject /// /// These properties are computed by message store or transport providers from the PR_SUBJECT (PidTagSubject) /// and PR_SUBJECT_PREFIX (PidTagSubjectPrefix) properties in the following manner. If the PR_SUBJECT_PREFIX /// is present and is an initial substring of PR_SUBJECT, PR_NORMALIZED_SUBJECT and associated properties are /// set to the contents of PR_SUBJECT with the prefix removed. If PR_SUBJECT_PREFIX is present, but it is not /// an initial substring of PR_SUBJECT, PR_SUBJECT_PREFIX is deleted and recalculated from PR_SUBJECT using /// the following rule: If the string contained in PR_SUBJECT begins with one to three non-numeric characters /// followed by a colon and a space, then the string together with the colon and the blank becomes the prefix. /// Numbers, blanks, and punctuation characters are not valid prefix characters. If PR_SUBJECT_PREFIX is not /// present, it is calculated from PR_SUBJECT using the rule outlined in the previous step.This property then /// is set to the contents of PR_SUBJECT with the prefix removed. /// /// /// When PR_SUBJECT_PREFIX is an empty string, PR_SUBJECT and PR_NORMALIZED_SUBJECT are the same. Ultimately, /// this property should be the part of PR_SUBJECT following the prefix. If there is no prefix, this property /// becomes the same as PR_SUBJECT. /// protected void SetSubject() { if (!string.IsNullOrEmpty(SubjectPrefix) && !string.IsNullOrEmpty(Subject)) { if (Subject.StartsWith(SubjectPrefix)) { SubjectNormalized = Subject.Substring(SubjectPrefix.Length); } else { var matches = SubjectPrefixRegex.Matches(Subject); if (matches.Count > 0) { SubjectPrefix = matches.OfType().First().Groups[1].Value; SubjectNormalized = matches.OfType().First().Groups[2].Value; } } } else if (!string.IsNullOrEmpty(Subject)) { var matches = SubjectPrefixRegex.Matches(Subject); if (matches.Count > 0) { SubjectPrefix = matches.OfType().First().Groups[1].Value; SubjectNormalized = matches.OfType().First().Groups[2].Value; } else SubjectNormalized = Subject; } else SubjectNormalized = Subject; SubjectPrefix ??= string.Empty; } #endregion #region WriteToStorage /// /// Writes all the properties that are part of the object either as 's /// or 's to the /// internal void WriteToStorage() { var rootStorage = CompoundFile; if (Class == MessageClass.Unknown) Class = MessageClass.IPM_Note; MessageSize += Recipients.WriteToStorage(rootStorage); MessageSize += Attachments.WriteToStorage(rootStorage); var recipientCount = Recipients.Count; var attachmentCount = Attachments.Count; TopLevelProperties.RecipientCount = recipientCount; TopLevelProperties.AttachmentCount = attachmentCount; TopLevelProperties.NextRecipientId = recipientCount; TopLevelProperties.NextAttachmentId = attachmentCount; TopLevelProperties.AddProperty(PropertyTags.PR_ENTRYID, Mapi.GenerateEntryId()); TopLevelProperties.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey()); TopLevelProperties.AddProperty(PropertyTags.PR_STORE_SUPPORT_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE); TopLevelProperties.AddProperty(PropertyTags.PR_STORE_UNICODE_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE); TopLevelProperties.AddProperty(PropertyTags.PR_ALTERNATE_RECIPIENT_ALLOWED, true, PropertyFlags.PROPATTR_READABLE); TopLevelProperties.AddProperty(PropertyTags.PR_HASATTACH, attachmentCount > 0); if (TransportMessageHeaders != null) { TopLevelProperties.AddProperty(PropertyTags.PR_TRANSPORT_MESSAGE_HEADERS_W, TransportMessageHeaders.ToString()); if (!string.IsNullOrWhiteSpace(TransportMessageHeaders.MessageId)) TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, TransportMessageHeaders.MessageId); if (TransportMessageHeaders.References.Any()) TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_REFERENCES_W, TransportMessageHeaders.References.Last()); if (TransportMessageHeaders.InReplyTo.Any()) TopLevelProperties.AddProperty(PropertyTags.PR_IN_REPLY_TO_ID_W, TransportMessageHeaders.InReplyTo.Last()); } if (!string.IsNullOrWhiteSpace(InternetMessageId)) TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, InternetMessageId); if (!string.IsNullOrWhiteSpace(InternetReferences)) TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_INTERNET_REFERENCES_W, InternetReferences); if (!string.IsNullOrWhiteSpace(InReplyToId)) TopLevelProperties.AddOrReplaceProperty(PropertyTags.PR_IN_REPLY_TO_ID_W, InReplyToId); var messageFlags = MessageFlags.MSGFLAG_UNMODIFIED; if (attachmentCount > 0) messageFlags |= MessageFlags.MSGFLAG_HASATTACH; TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_CPID, Encoding.UTF8.CodePage); TopLevelProperties.AddProperty(PropertyTags.PR_BODY_W, BodyText); if (!string.IsNullOrEmpty(BodyHtml) && !Draft) { TopLevelProperties.AddProperty(PropertyTags.PR_HTML, BodyHtml); TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, false); } else if (string.IsNullOrWhiteSpace(BodyRtf) && !string.IsNullOrWhiteSpace(BodyHtml)) { BodyRtf = Encapsulator.Encapsulate(BodyHtml); BodyRtfCompressed = true; } if (!string.IsNullOrWhiteSpace(BodyRtf)) { TopLevelProperties.AddProperty(PropertyTags.PR_RTF_COMPRESSED, new Compressor().Compress(Encoding.ASCII.GetBytes(BodyRtf))); TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, BodyRtfCompressed); } if (MessageEditorFormat != MessageEditorFormat.EDITOR_FORMAT_DONTKNOW) TopLevelProperties.AddProperty(PropertyTags.PR_MSG_EDITOR_FORMAT, MessageEditorFormat); if (ReceivedOn.HasValue && ReceivedOn > DateTime.MinValue) TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_DELIVERY_TIME, ReceivedOn.Value.ToUniversalTime()); if (SentOn.HasValue && SentOn > DateTime.MinValue) TopLevelProperties.AddProperty(PropertyTags.PR_CLIENT_SUBMIT_TIME, SentOn.Value.ToUniversalTime()); TopLevelProperties.AddProperty(PropertyTags.PR_ACCESS, MapiAccess.MAPI_ACCESS_DELETE | MapiAccess.MAPI_ACCESS_MODIFY | MapiAccess.MAPI_ACCESS_READ); TopLevelProperties.AddProperty(PropertyTags.PR_ACCESS_LEVEL, MapiAccess.MAPI_ACCESS_MODIFY); TopLevelProperties.AddProperty(PropertyTags.PR_OBJECT_TYPE, MapiObjectType.MAPI_MESSAGE); SetSubject(); TopLevelProperties.AddProperty(PropertyTags.PR_SUBJECT_W, Subject); TopLevelProperties.AddProperty(PropertyTags.PR_NORMALIZED_SUBJECT_W, SubjectNormalized); TopLevelProperties.AddProperty(PropertyTags.PR_SUBJECT_PREFIX_W, SubjectPrefix); TopLevelProperties.AddProperty(PropertyTags.PR_CONVERSATION_TOPIC_W, SubjectNormalized); // http://www.meridiandiscovery.com/how-to/e-mail-conversation-index-metadata-computer-forensics/ // http://stackoverflow.com/questions/11860540/does-outlook-embed-a-messageid-or-equivalent-in-its-email-elements //propertiesStream.AddProperty(PropertyTags.PR_CONVERSATION_INDEX, Subject); // TODO: Change modification time when this message is opened and only modified var utcNow = DateTime.UtcNow; TopLevelProperties.AddProperty(PropertyTags.PR_CREATION_TIME, utcNow); TopLevelProperties.AddProperty(PropertyTags.PR_LAST_MODIFICATION_TIME, utcNow); TopLevelProperties.AddProperty(PropertyTags.PR_PRIORITY, Priority); TopLevelProperties.AddProperty(PropertyTags.PR_IMPORTANCE, Importance); TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_LOCALE_ID, CultureInfo.CurrentCulture.LCID); if (Draft) { messageFlags |= MessageFlags.MSGFLAG_UNSENT; // Only set the IconIndex when it is not changed from NewEmail to something else if (IconIndex == MessageIconIndex.NewMail) IconIndex = MessageIconIndex.UnsentMail; } if (ReadRecipient) { TopLevelProperties.AddProperty(PropertyTags.PR_READ_RECEIPT_REQUESTED, true); var reportTag = new ReportTag { ANSIText = Subject }; TopLevelProperties.AddProperty(PropertyTags.PR_REPORT_TAG, reportTag.ToByteArray()); } TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_FLAGS, messageFlags); TopLevelProperties.AddProperty(PropertyTags.PR_ICON_INDEX, IconIndex); Sender?.WriteProperties(TopLevelProperties); Receiving?.WriteProperties(TopLevelProperties); Representing?.WriteProperties(TopLevelProperties); ReceivingRepresenting?.WriteProperties(TopLevelProperties); if (recipientCount > 0) { var displayTo = new List(); var displayCc = new List(); var displayBcc = new List(); foreach (var recipient in Recipients) { switch (recipient.RecipientType) { case RecipientType.To: if (!string.IsNullOrWhiteSpace(recipient.DisplayName)) displayTo.Add(recipient.DisplayName); else if (!string.IsNullOrWhiteSpace(recipient.Email)) displayTo.Add(recipient.Email); break; case RecipientType.Cc: if (!string.IsNullOrWhiteSpace(recipient.DisplayName)) displayCc.Add(recipient.DisplayName); else if (!string.IsNullOrWhiteSpace(recipient.Email)) displayCc.Add(recipient.Email); break; case RecipientType.Bcc: if (!string.IsNullOrWhiteSpace(recipient.DisplayName)) displayBcc.Add(recipient.DisplayName); else if (!string.IsNullOrWhiteSpace(recipient.Email)) displayBcc.Add(recipient.Email); break; default: throw new ArgumentOutOfRangeException(); } } var replyToRecipients = new List(); foreach (var recipient in ReplyToRecipients) { replyToRecipients.Add(recipient.Email); } TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_TO_W, string.Join(";", displayTo), PropertyFlags.PROPATTR_READABLE); TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_CC_W, string.Join(";", displayCc), PropertyFlags.PROPATTR_READABLE); TopLevelProperties.AddProperty(PropertyTags.PR_DISPLAY_BCC_W, string.Join(";", displayBcc), PropertyFlags.PROPATTR_READABLE); TopLevelProperties.AddProperty(PropertyTags.PR_REPLY_RECIPIENT_NAMES_W, string.Join(";", replyToRecipients), PropertyFlags.PROPATTR_READABLE); } } #endregion #region Save /// /// Saves the message to the given /// /// public new void Save(Stream stream) { WriteToStorage(); base.Save(stream); } /// /// Saves the message to the given /// /// public new void Save(string fileName) { WriteToStorage(); base.Save(fileName); } #endregion #region Dispose /// /// Disposes all the attachment streams /// public new void Dispose() { if (!_leaveAttachmentStreamsOpen) foreach (var attachment in _attachments) attachment.Stream?.Dispose(); base.Dispose(); } #endregion } ================================================ FILE: MsgKit/Enums/AddressBookEntryIdType.cs ================================================ // // AddressBookEntryIdType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// An integer representing the type of the object. It MUST be one of the values from the following table. /// public enum AddressBookEntryIdType { /// /// A local mail user /// LocalMailUser = 0x00000000, /// /// A distribution list /// DistributionList = 0x00000001, /// /// A bulletinboard or public folder /// BulletinBoardOrPublicFolder = 0x00000002, /// /// An automated mailbox /// AutomatedMailBox = 0x00000003, /// /// An organiztional mailbox /// OrganizationalMailBox = 0x00000004, /// /// A private distribtion list /// PrivateDistributionList = 0x00000005, /// /// A remote mail user /// RemoteMailUser = 0x00000006, /// /// A container /// Container = 0x00000100, /// /// A template /// Template = 0x00000101, /// /// One off user /// OneOffUser = 0x00000102, /// /// Search /// Search = 0x00000200 } ================================================ FILE: MsgKit/Enums/AddressType.cs ================================================ // // AddressType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Contains the messaging user's e-mail address type, such as SMTP. /// public enum AddressType { /// /// Unknown /// Unknown, /// /// Exchange /// Ex, /// /// Simple Mail Transfer Protocol /// Smtp, /// /// Fax /// Fax, /// /// MHS /// Mhs, /// /// PROFS /// Profs, /// /// X400 /// X400 } ================================================ FILE: MsgKit/Enums/AppointmentState.cs ================================================ // ReSharper disable InconsistentNaming // // AppointmentState.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/cc815362(v=office.15).aspx /// public enum AppointmentState : uint { /// /// This flag indicates that the object is a meeting object or a meeting-related object. /// asfMeeting = 0x00000001, /// /// This flag indicates that the represented object was received from someone else. /// asfReceived = 0x00000002, /// /// This flag indicates that the meeting object represented by the object has been canceled. /// asfCanceled = 0x00000004, /// /// Full update. /// mtgInfo = 0x00020000, /// /// A newer meeting request or meeting update was received after this one. /// mtgOutOfDate = 0x00080000, /// /// This is set on the delegators copy when a delegate handles meeting-related objects. /// mtgDelegatorCopy = 0x00100000 } ================================================ FILE: MsgKit/Enums/AttachmentFlags.cs ================================================ // ReSharper disable InconsistentNaming // // AttachmentType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Contains a bitmask of flags for an attachment. /// /// /// See https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2007/cc765876(v=office.12) /// public enum AttachmentFlags : uint { /// /// Indicates that this attachment is not available to HTML rendering applications and should be ignored in /// Multipurpose Internet Mail Extensions (MIME) processing. /// ATT_INVISIBLE_IN_HTML = 0x00000001, /// /// Indicates that this attachment is not available to applications rendering in Rich Text Format (RTF) and should be /// ignored by MAPI. /// ATT_INVISIBLE_IN_RTF = 0x00000002, /// /// The Attachment object is referenced and rendered within the HTML body of the associated Message object. /// ATT_MHTML_REF = 0x00000004 } ================================================ FILE: MsgKit/Enums/AttachmentType.cs ================================================ // ReSharper disable InconsistentNaming // // AttachmentType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// The type of the attachment /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc815439.aspx /// public enum AttachmentType : uint { /// /// There is no attachment /// NO_ATTACHMENT = 0x00000000, /// /// The property contains the attachment data /// ATTACH_BY_VALUE = 0x00000001, /// /// The or /// property contains a fully qualified path identifying the attachment to recipients with access to a common file server /// ATTACH_BY_REFERENCE = 0x0002, /// /// The or /// property contains a fully qualified path identifying the attachment /// ATTACH_BY_REF_RESOLVE = 0x0003, /// /// The or /// property contains a fully qualified path identifying the attachment /// ATTACH_BY_REF_ONLY = 0x0004, /// /// The (PidTagAttachDataObject) property contains an embedded object /// that supports the IMessage interface /// ATTACH_EMBEDDED_MSG = 0x0005, /// /// The attachment is an embedded OLE object /// ATTACH_OLE = 0x0006, /// /// The property contains a fully qualified path identifying the attachment. /// The PidNameAttachmentProviderType defines the web service API manipulating the attachment. /// ATTACH_BY_WEB_REFERENCE = 0x0007 } ================================================ FILE: MsgKit/Enums/MapiAccess.cs ================================================ // // MapiAccess.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// Contains a bitmask of flags indicating the operations that are available to the client for the object. /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc979218.aspx /// This property is read-only for the client. It must be a bitwise OR of zero or more values from the following table. /// [Flags] public enum MapiAccess : uint { /// /// Write /// MAPI_ACCESS_MODIFY = 0x00000001, /// /// Read /// MAPI_ACCESS_READ = 0x00000002, /// /// Delete /// MAPI_ACCESS_DELETE = 0x00000004, /// /// Create subfolders in the folder hierarchy /// MAPI_ACCESS_CREATE_HIERARCHY = 0x00000008, /// /// Create content messages /// MAPI_ACCESS_CREATE_CONTENTS = 0x00000010, /// /// Create associated content messages /// MAPI_ACCESS_CREATE_ASSOCIATED = 0x00000020 } ================================================ FILE: MsgKit/Enums/MapiObjectType.cs ================================================ // // MapiObjectType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// Contains the type of an object. /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc815487.aspx /// The object type contained in this property corresponds to the primary interface available for an object accessible /// through the OpenEntry interface. It is usually obtained by consulting the lpulObjType parameter returned by the /// appropriate OpenEntry method. When the interface is obtained in other ways, call IMAPIProp::GetProps to obtain the /// value for this property. /// [Flags] public enum MapiObjectType : uint { /// /// Address book container object /// MAPI_ABCONT = 4, /// /// Address book object /// MAPI_ADDRBOOK = 2, /// /// Message attachment object /// MAPI_ATTACH = 7, /// /// Distribution list object /// MAPI_DISTLIST = 8, /// /// Folder object /// MAPI_FOLDER = 3, /// /// Form object /// MAPI_FORMINFO = 12, /// /// Messaging user object /// MAPI_MAILUSER = 6, /// /// Message object /// MAPI_MESSAGE = 5, /// /// Profile section object /// MAPI_PROFSECT = 9, /// /// Session object /// MAPI_SESSION = 11, /// /// Status object /// MAPI_STATUS = 10, /// /// Message store object /// MAPI_STORE = 1 } ================================================ FILE: MsgKit/Enums/MeetingType.cs ================================================ // ReSharper disable InconsistentNaming // // MeetingType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/cc815362(v=office.15).aspx /// public enum MeetingType : uint { /// /// Unspecified. /// mtgEmpty = 0x00000000, /// /// nitial meeting request. /// mtgRequest = 0x00000001, /// /// Full update. /// mtgFull = 0x00010000, /// /// Full update. /// mtgInfo = 0x00020000, /// /// A newer meeting request or meeting update was received after this one. /// mtgOutOfDate = 0x00080000, /// /// This is set on the delegators copy when a delegate handles meeting-related objects. /// mtgDelegatorCopy = 0x00100000 } ================================================ FILE: MsgKit/Enums/MessageClass.cs ================================================ // // MessageClass.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// The MessageClass element is an optional element that specifies the message class of this e-mail message. /// /// /// See https://msdn.microsoft.com/en-us/library/ee200767(v=exchg.80).aspx /// public enum MessageClass { /// /// The message type is unknown /// Unknown, /// /// Normal e-mail message. /// IPM_Note, /// /// The message is encrypted and can also be signed. /// IPM_Note_SMIME, /// /// The message is clear signed. /// IPM_Note_SMIME_MultipartSigned, /// /// The message is a secure read receipt. /// IPM_Note_Receipt_SMIME, /// /// Post. /// IPM_Post, /// /// Octel voice message. /// IPM_Octel_Voice, /// /// Electronic voice notes. /// IPM_Voicenotes, /// /// Shared message. /// IPM_Sharing, /// /// Non-delivery report for a standard message. /// REPORT_IPM_NOTE_NDR, /// /// Delivery receipt for a standard message. /// REPORT_IPM_NOTE_DR, /// /// Delivery receipt for a delayed message. /// REPORT_IPM_NOTE_DELAYED, /// /// Read receipt for a standard message. /// REPORT_IPM_NOTE_IPNRN, /// /// Non-read receipt for a standard message. /// REPORT_IPM_NOTE_IPNNRN, /// /// Non-delivery report for a meeting request. /// REPORT_IPM_SCHEDULE_MEETING_REQUEST_NDR, /// /// Non-delivery report for a positive meeting response (accept). /// REPORT_IPM_SCHEDULE_MEETING_RESP_POS_NDR, /// /// Non-delivery report for a Tentative meeting response. /// REPORT_IPM_SCHEDULE_MEETING_RESP_TENT_NDR, /// /// Non-delivery report for a cancelled meeting notification. /// REPORT_IPM_SCHEDULE_MEETING_CANCELED_NDR, /// /// Non-delivery report for a Secure MIME (S/MIME) encrypted and opaque-signed message. /// REPORT_IPM_NOTE_SMIME_NDR, /// /// Delivery receipt for an S/MIME encrypted and opaque-signed message. /// REPORT_IPM_NOTE_SMIME_DR, /// /// Non-delivery report for an S/MIME clear-signed message. /// REPORT_IPM_NOTE_SMIME_MULTIPARTSIGNED_NDR, /// /// Delivery receipt for an S/MIME clear-signed message. /// REPORT_IPM_NOTE_SMIME_MULTIPARTSIGNED_DR, /// /// An appointment /// IPM_Appointment, /// /// Task /// IPM_Task, /// /// A contact /// IPM_Contact } ================================================ FILE: MsgKit/Enums/MessageEditorFormat.cs ================================================ // // MessageEditorFormat.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// Specifies the format for an editor to use to display a message. /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc765727.aspx /// public enum MessageEditorFormat { /// /// The format for the editor to use is unknown. /// EDITOR_FORMAT_DONTKNOW = 0x00000000, /// /// The editor should display the message in plain text format. /// EDITOR_FORMAT_PLAINTEXT = 0x00000001, /// /// The editor should display the message in HTML format. /// EDITOR_FORMAT_HTML = 0x00000002, /// /// The editor should display the message in Rich Text Format. /// EDITOR_FORMAT_RTF = 0x00000003 } ================================================ FILE: MsgKit/Enums/MessageFlags.cs ================================================ // // MessageFlags.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// Contains a bitmask of flags that indicate the origin and current state of a message. /// /// /// See https://msdn.microsoft.com/en-us/library/cc839733(v=office.15).aspx /// This property is a nontransmittable message property exposed at both the sending and receiving ends of a /// transmission, with different values depending upon the client application or store provider involved. This property /// is initialized by the client or message store provider when a message is created and saved for the first time and /// then updated periodically by the message store provider, a transport provider, and the MAPI spooler as the message /// is processed and its state changes. /// This property exists on a message both before and after submission, and on all copies of the received /// message. Although it is not a recipient property, it is exposed differently to each recipient according to whether /// it has been read or modified by that recipient. /// [Flags] public enum MessageFlags : uint { /// /// The message is marked as having been read. This can occur as the result of a call at any time to /// IMessage::SetReadFlag or IMAPIFolder::SetReadFlags. Clients can also set this flag by calling a message's /// IMAPIProp::SetProps method before the message has been saved for the first time. This flag is ignored if the /// ASSOCIATED flag is set. /// MSGFLAG_READ = 0x0001, /// /// The outgoing message has not been modified since the first time that it was saved; the incoming message has not /// been modified since it was delivered. /// MSGFLAG_UNMODIFIED = 0x0002, /// /// The message is marked for sending as a result of a call to IMessage::SubmitMessage. Message store providers set /// this flag; the client has read-only access. /// MSGFLAG_SUBMIT = 0x0004, /// /// The message is still being composed. It is saved, but has not been sent. The client or provider has read/write /// access to this flag until the first IMAPIProp::SaveChanges call and read-only thereafter. If a client doesn't set /// this flag by the time the message is sent, the message store provider sets it when IMessage::SubmitMessage is /// called. Typically, this flag is cleared after the message is sent. /// MSGFLAG_UNSENT = 0x0008, /// /// The message has at least one attachment. This flag corresponds to the message's PR_HASATTACH (PidTagHasAttachments) /// property. The client has read-only access to this flag. /// MSGFLAG_HASATTACH = 0x0010, /// /// The messaging user sending was the messaging user receiving the message. The client or provider has read/write /// access to this flag until the first IMAPIProp::SaveChanges call and read-only thereafter. This flag is meant to be /// set by the transport provider. /// MSGFLAG_FROMME = 0x0020, /// /// The message is an associated message of a folder. The client or provider has read-only access to this flag. The /// READ flag is ignored for associated messages, which do not retain a read/unread state. /// MSGFLAG_ASSOCIATED = 0x040, /// /// The message includes a request for a resend operation with a nondelivery report. The client or provider has /// read/write access to this flag until the first IMAPIProp::SaveChanges call and read-only thereafter. /// MSGFLAG_RESEND = 0x0080, /// /// A read report needs to be sent for the message. The client or provider has read-only access to this flag. /// MSGFLAG_NOTIFYREAD = 0x100, /// /// A nonread report needs to be sent for the message. The client or provider has read-only access to this flag. /// MSGFLAG_NOTIFYUNREAD = 0x0200, /// /// The message has been read at least once. This flag is set or cleared by the server whenever the MSGFLAG_READ flag /// is set or cleared. /// MSGFLAG_EVERREAD = 0x0400, /// /// The incoming message arrived over an X.400 link. It originated either outside the organization or from a source the /// gateway cannot consider trusted. The client should display an appropriate message to the user. Transport providers /// set this flag; the client has read-only access. /// MSGFLAG_ORIGIN_X400 = 0x1000, /// /// The incoming message arrived over the Internet. It originated either outside the organization or from a source the /// gateway cannot consider trusted. The client should display an appropriate message to the user. Transport providers /// set this flag; the client has read-only access. /// MSGFLAG_ORIGIN_INTERNET = 0x2000, /// /// The incoming message arrived over an external link other than X.400 or the Internet. It originated either outside /// the organization or from a source the gateway cannot consider trusted. The client should display an appropriate /// message to the user. Transport providers set this flag; the client has read-only access. /// MSGFLAG_ORIGIN_MISC_EXT = 0x8000 } ================================================ FILE: MsgKit/Enums/MessageFormat.cs ================================================ // // MessageFormat.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// The messageformat to use /// public enum MessageFormat { /// /// Send a plain text message body. /// TextOnly, /// /// Send an HTML message body. /// HtmlOnly, /// /// Send a multipart / alternative body with both plain text and HTML. /// TextAndHtml } ================================================ FILE: MsgKit/Enums/MessageIconIndex.cs ================================================ // // MessageIconIndex.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Enums; /// /// Contains a number that indicates which icon to use when you display a group of e-mail objects. /// /// /// See https://msdn.microsoft.com/en-us/library/cc815472(v=office.15).aspx /// This property, if it exists, is a hint to the client. The client may ignore the value of this property. /// [Flags] public enum MessageIconIndex : uint { /// /// New mail /// NewMail = 0x00000000, /// /// Post /// Post = 0x00000001, /// /// Other /// Other = 0x00000003, /// /// Read mail /// ReadMail = 0x00000100, /// /// Unread mail /// UnreadMail = 0x00000101, /// /// Submitted mail /// SubmittedMail = 0x00000102, /// /// Unsent mail /// UnsentMail = 0x00000103, /// /// Receipt mail /// ReceiptMail = 0x00000104, /// /// Replied mail /// RepliedMail = 0x00000105, /// /// Forwarded mail /// ForwardedMail = 0x00000106, /// /// Remote mail /// RemoteMail = 0x00000107, /// /// Delivery receipt /// DeliveryReceipt = 0x00000108, /// /// Read receipt /// ReadReceipt = 0x00000109, /// /// Non delivery report /// NondeliveryReport = 0x0000010A, /// /// Non read receipt /// NonReadReceipt = 0x0000010B, /// /// Recall S mail /// RecallSMail = 0x0000010C, /// /// Recall F mail /// RecallFMail = 0x0000010D, /// /// Tracking mail /// TrackingMail = 0x0000010E, /// /// Out of office mail /// OutOfOfficeMail = 0x0000011B, /// /// Recall mail /// RecallMail = 0x0000011C, /// /// Tracked mail /// TrackedMail = 0x00000130, /// /// Contact /// Contact = 0x00000200, /// /// Distribution list /// DistributionList = 0x00000202, /// /// Sticky note blue /// StickyNoteBlue = 0x00000300, /// /// Sticky note green /// StickyNoteGreen = 0x00000301, /// /// Sticky note pink /// StickyNotePink = 0x00000302, /// /// Sticky note yellow /// StickyNoteYellow = 0x00000303, /// /// Sticky note white /// StickyNoteWhite = 0x00000304, /// /// Single instance appointment /// SingleInstanceAppointment = 0x00000400, /// /// Recurring appointment /// RecurringAppointment = 0x00000401, /// /// Single instance meeting /// SingleInstanceMeeting = 0x00000402, /// /// Recurring meeting /// RecurringMeeting = 0x00000403, /// /// Meeting request /// MeetingRequest = 0x00000404, /// /// Accept /// Accept = 0x00000405, /// /// Decline /// Decline = 0x00000406, /// /// Tentativly /// Tentativly = 0x00000407, /// /// Cancellation /// Cancellation = 0x00000408, /// /// Informational update /// InformationalUpdate = 0x00000409, /// /// Task/task /// TaskTask = 0x00000500, /// /// Unassigned recurring task /// UnassignedRecurringTask = 0x00000501, /// /// Assignee's task /// AssigneesTask = 0x00000502, /// /// Assigner's task /// AssignersTask = 0x00000503, /// /// Task request /// TaskRequest = 0x00000504, /// /// Task acceptance /// TaskAcceptance = 0x00000505, /// /// Task rejection /// TaskRejection = 0x00000506, /// /// Journal conversation /// JournalConversation = 0x00000601, /// /// Journal e-mail message /// JournalEmailMessage = 0x00000602, /// /// Journal meeting request /// JournalMeetingRequest = 0x00000603, /// /// Journal meeting response /// JournalMeetingResponse = 0x00000604, /// /// Journal task request /// JournalTaskRequest = 0x00000606, /// /// Journal task response /// JournalTaskResponse = 0x00000607, /// /// Journal note /// JournalNote = 0x00000608, /// /// Journal fax /// JournalFax = 0x00000609, /// /// Journal phone call /// JournalPhoneCall = 0x0000060A, /// /// Journal letter /// JournalLetter = 0x0000060C, /// /// Journal Microsoft Office Word /// JournalMicrosoftOfficeWord = 0x0000060D, /// /// Journal Microsoft Office Excel /// JournalMicrosoftOfficeExcel = 0x0000060E, /// /// Journal Microsoft Office PowerPoint /// JournalMicrosoftOfficePowerPoint = 0x0000060F, /// /// Journal Microsoft Office Access /// JournalMicrosoftOfficeAccess = 0x00000610, /// /// Journal document /// JournalDocument = 0x00000612, /// /// Journal meeting /// JournalMeeting = 0x00000613, /// /// Journal meeting cancellation /// JournalMeetingCancellation = 0x00000614, /// /// Journal remote session /// JournalRemoteSession = 0x00000615 } ================================================ FILE: MsgKit/Enums/MessageImportance.cs ================================================ // // MessageImportance.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// Contains the relative priority of a message. /// /// /// See https://msdn.microsoft.com/en-us/library/cc815346(v=office.15).aspx /// public enum MessageImportance { /// /// The message has low importance. /// IMPORTANCE_LOW = 0, /// /// The message has normal importance. /// IMPORTANCE_NORMAL = 1, /// /// The message has high importance. /// IMPORTANCE_HIGH = 2 } ================================================ FILE: MsgKit/Enums/MessagePriority.cs ================================================ // // MessagePriority.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// Contains a value that indicates the message sender's opinion of the importance of a message. /// /// /// See https://msdn.microsoft.com/en-us/library/cc765646(v=office.15).aspx /// public enum MessagePriority { /// /// The message is not urgent. /// PRIO_NONURGENT = 0, /// /// The message has normal priority. /// PRIO_NORMAL = 1, /// /// The message is urgent. /// PRIO_URGENT = 2 } ================================================ FILE: MsgKit/Enums/PostalAddressId.cs ================================================ // ReSharper disable InconsistentNaming // // PostalAddressId.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Specifies which physical address is the contact's mailing address /// /// /// See https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/pidlidpostaladdressid-canonical-property /// public enum PostalAddressId : uint { /// /// No address is selected as the mailing address /// NO_ADDRESS = 0x00000000, /// /// The Home Address is the mailing address /// HOME_ADDRESS = 0x00000001, /// /// The Work Address is the mailing address. /// WORK_ADDRESS = 0x00000002, /// /// The Other Address is the mailing address /// OTHER_ADDRESS = 0x00000003, } ================================================ FILE: MsgKit/Enums/PropertyFlags.cs ================================================ // // PropertyFlags.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Enums; /// /// Flags used to set on a /// /// /// See https://msdn.microsoft.com/en-us/library/ee158556(v=exchg.80).aspx /// [Flags] public enum PropertyFlags : uint { // ReSharper disable InconsistentNaming /// /// If this flag is set for a property, that property MUST NOT be deleted from the .msg file /// (irrespective of which storage it is contained in) and implementations MUST return an error /// if any attempt is made to do so. This flag is set in circumstances where the implementation /// depends on that property always being present in the .msg file once it is written there. /// PROPATTR_MANDATORY = 0x00000001, /// /// If this flag is not set on a property, that property MUST NOT be read from the .msg file /// and implementations MUST return an error if any attempt is made to read it. This flag is /// set on all properties unless there is an implementation-specific reason to prevent a property /// from being read from the .msg file. /// PROPATTR_READABLE = 0x00000002, /// /// If this flag is not set on a property, that property MUST NOT be modified or deleted and /// implementations MUST return an error if any attempt is made to do so. This flag is set in /// circumstances where the implementation depends on the properties being writable. /// PROPATTR_WRITABLE = 0x00000004 // ReSharper restore InconsistentNaming } ================================================ FILE: MsgKit/Enums/PropertyKind.cs ================================================ // // PropertyKind.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Enums; /// /// Kind (1 byte): The possible values for the Kind field are in the following table. /// [Flags] public enum PropertyKind { /// /// The property is identified by the LID field (numerical named property) /// Lid = 0x00, /// /// The property is identified by the Name field (string named property) /// Name = 0x01, /// /// The property does not have an associated PropertyName field. /// NotAssociated = 0xFF } ================================================ FILE: MsgKit/Enums/PropertyType.cs ================================================ // // PropertyType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// The type of a property in the properties stream /// public enum PropertyType : ushort { /// /// Any: this property type value matches any type; a server MUST return the actual type in its response. Servers /// MUST NOT return this type in response to a client request other than NspiGetIDsFromNames or the /// RopGetPropertyIdsFromNamesROP request ([MS-OXCROPS] section 2.2.8.1). (PT_UNSPECIFIED) /// PT_UNSPECIFIED = 0x0000, /// /// None: This property is a placeholder. (PT_NULL) /// PT_NULL = 0x0001, /// /// 2 bytes; a 16-bit integer (PT_I2, i2, ui2) /// PT_SHORT = 0x0002, /// /// 4 bytes; a 32-bit integer (PT_LONG, PT_I4, int, ui4) /// PT_LONG = 0x0003, /// /// 4 bytes; a 32-bit floating point number (PT_FLOAT, PT_R4, float, r4) /// PT_FLOAT = 0x0004, /// /// 8 bytes; a 64-bit floating point number (PT_DOUBLE, PT_R8, r8) /// PT_DOUBLE = 0x0005, /// /// 8 bytes; a 64-bit floating point number in which the whole number part represents the number of days since /// December 30, 1899, and the fractional part represents the fraction of a day since midnight (PT_APPTIME) /// PT_APPTIME = 0x0007, /// /// 4 bytes; a 32-bit integer encoding error information as specified in section 2.4.1. (PT_ERROR) /// PT_ERROR = 0x000A, /// /// 1 byte; restricted to 1 or 0 (PT_BOOLEAN. bool) /// PT_BOOLEAN = 0x000B, /// /// The property value is a Component Object Model (COM) object, as specified in section 2.11.1.5. (PT_OBJECT) /// PT_OBJECT = 0x000D, /// /// 8 bytes; a 64-bit integer (PT_LONGLONG, PT_I8, i8, ui8) /// PT_I8 = 0x0014, /// /// 8 bytes; a 64-bit integer (PT_LONGLONG, PT_I8, i8, ui8) /// PT_LONGLONG = 0x0014, /// /// Variable size; a string of Unicode characters in UTF-16LE format encoding with terminating null character /// (0x0000). (PT_UNICODE, string) /// PT_UNICODE = 0x001F, /// /// Variable size; a string of multibyte characters in externally specified encoding with terminating null /// character (single 0 byte). (PT_STRING8) ... ANSI format /// PT_STRING8 = 0x001E, /// /// 8 bytes; a 64-bit integer representing the number of 100-nanosecond intervals since January 1, 1601 /// (PT_SYSTIME, time, datetime, datetime.tz, datetime.rfc1123, Date, time, time.tz) /// PT_SYSTIME = 0x0040, /// /// 16 bytes; a GUID with Data1, Data2, and Data3 fields in little-endian format (PT_CLSID, UUID) /// PT_CLSID = 0x0048, /// /// Variable size; a 16-bit COUNT field followed by a structure as specified in section 2.11.1.4. (PT_SVREID) /// PT_SVREID = 0x00FB, /// /// Variable size; a byte array representing one or more Restriction structures as specified in section 2.12. /// (PT_SRESTRICT) /// PT_SRESTRICT = 0x00FD, /// /// Variable size; a 16-bit COUNT field followed by that many rule (4) action (3) structures, as specified in /// [MS-OXORULE] section 2.2.5. (PT_ACTIONS) /// PT_ACTIONS = 0x00FE, /// /// Variable size; a COUNT field followed by that many bytes. (PT_BINARY) /// PT_BINARY = 0x0102, /// /// Variable size; a COUNT field followed by that many PT_MV_SHORT values. (PT_MV_SHORT, PT_MV_I2, mv.i2) /// PT_MV_SHORT = 0x1002, /// /// Variable size; a COUNT field followed by that many PT_MV_LONG values. (PT_MV_LONG, PT_MV_I4, mv.i4) /// PT_MV_LONG = 0x1003, /// /// Variable size; a COUNT field followed by that many PT_MV_FLOAT values. (PT_MV_FLOAT, PT_MV_R4, mv.float) /// PT_MV_FLOAT = 0x1004, /// /// Variable size; a COUNT field followed by that many PT_MV_DOUBLE values. (PT_MV_DOUBLE, PT_MV_R8) /// PT_MV_DOUBLE = 0x1005, /// /// Variable size; a COUNT field followed by that many PT_MV_CURRENCY values. (PT_MV_CURRENCY, mv.fixed.14.4) /// PT_MV_CURRENCY = 0x1006, /// /// Variable size; a COUNT field followed by that many PT_MV_APPTIME values. (PT_MV_APPTIME) /// PT_MV_APPTIME = 0x1007, /// /// Variable size; a COUNT field followed by that many PT_MV_LONGLONGvalues. (PT_MV_I8, PT_MV_I8) /// PT_MV_LONGLONG = 0x1014, /// /// Variable size; a COUNT field followed by that many PT_MV_UNICODE values. (PT_MV_UNICODE) /// PT_MV_TSTRING = 0x101F, /// /// Variable size; a COUNT field followed by that many PT_MV_UNICODE values. (PT_MV_UNICODE) /// PT_MV_UNICODE = 0x101F, /// /// Variable size; a COUNT field followed by that many PT_MV_STRING8 values. (PT_MV_STRING8, mv.string) /// PT_MV_STRING8 = 0x101E, /// /// Variable size; a COUNT field followed by that many PT_MV_SYSTIME values. (PT_MV_SYSTIME) /// PT_MV_SYSTIME = 0x1040, /// /// Variable size; a COUNT field followed by that many PT_MV_CLSID values. (PT_MV_CLSID, mv.uuid) /// PT_MV_CLSID = 0x1048, /// /// Variable size; a COUNT field followed by that many PT_MV_BINARY values. (PT_MV_BINARY, mv.bin.hex) /// PT_MV_BINARY = 0x1102, } ================================================ FILE: MsgKit/Enums/RecipientFlags.cs ================================================ // // RecipientFlags.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Enums; /// /// Specifies a bit field that describes the recipient status. /// /// /// See https://msdn.microsoft.com/en-us/library/office/cc815629.aspx /// [Flags] public enum RecipientFlags : uint { /// /// The recipient is a Sendable Attendee. This flag is only used in the dispidApptUnsendableRecips /// (PidLidAppointmentUnsendableRecipients) property. /// RecipSendable = 0x00000001, /// /// The RecipientRow on which this flag is set represents the meeting Organizer. /// RecipOrganizer = 0x0000002, /// /// Indicates that the attendee gave a response for the exception on which this RecipientRow resides. This flag is only /// used in a RecipientRow of an exception embedded message object of the organizers meeting object. /// RecipExceptionalResponse = 0x00000010, /// /// Indicates that although the RecipientRow exists, it should be treated as if the corresponding recipient does not. /// This flag is only used in a RecipientRow of an exception embedded message object of the organizers meeting object. /// RecipExceptionalDeleted = 0x00000020, /// /// Indicates the recipient is an original attendee. This flag is only used in the dispidApptUnsendableRecips property. /// RecipOriginal = 0x00000100 } ================================================ FILE: MsgKit/Enums/RecipientRowAddressType.cs ================================================ // // RecipientRowAddressType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using MsgKit.Structures; namespace MsgKit.Enums; /// /// The /// public enum RecipientRowAddressType { /// /// No type is set /// NoType = 0x0, /// /// X500DN /// X500Dn = 0x1, /// /// Ms mail /// MsMail = 0x2, /// /// SMTP /// Smtp = 0x3, /// /// Fax /// Fax = 0x4, /// /// Professional office system /// ProfessionalOfficeSystem = 0x5, /// /// Personal distribution list 1 /// PersonalDistributionList1 = 0x6, /// /// Personal distribution list 2 /// PersonalDistributionList2 = 0x7 } ================================================ FILE: MsgKit/Enums/RecipientRowDisplayType.cs ================================================ // // RecipientRowAddressType.cs // // Author: RecipientRowDisplayType and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// An enumeration. This field MUST be present when the Type field /// of the RecipientFlags field is set to X500DN(0x1) and MUST NOT be present otherwise.This /// value specifies the display type of this address.Valid values for this field are specified in the /// following table. /// public enum RecipientRowDisplayType { /// /// A messaging user /// MessagingUser = 0x00, /// /// A distribution list /// DistributionList = 0x01, /// /// A forum, such as a bulletin board service or a public or shared folder /// Forum = 0x02, /// /// An automated agent /// AutomatedAgent = 0x03, /// /// An Address Book object defined for a large group, such as helpdesk, accounting, coordinator, or /// department /// AddressBook = 0x04, /// /// A private, personally administered distribution list /// PrivateDistributionList = 0x05, /// /// An Address Book object known to be from a foreign or remote messaging system /// RemoteAddressBook = 0x06 } ================================================ FILE: MsgKit/Enums/RecipientType.cs ================================================ // // RecipientType.cs // // Author: RecipientRowDisplayType and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// The recipient type /// /// /// See https://msdn.microsoft.com/en-us/library/cc839620(v=office.15).aspx /// public enum RecipientType : uint { /// /// The recipient is the message originator /// Originator = 0x0000, /// /// The recipient is a primary (To) recipient. Clients are required to handle primary recipients. All other types are optional. /// To = 0x0001, /// /// The recipient is a carbon copy (CC) recipient, a recipient that receives a message in addition to the primary recipients. /// Cc = 0x0002, /// /// The recipient is a blind carbon copy (BCC) recipient. Primary and carbon copy recipients are unaware of the existence of BCC recipients. /// Bcc = 0x0003, /// /// The recipient is a resource (e.g. a room) /// Resource = 0x0004, /// /// The recipient is a room (uses PR_RECIPIENT_TYPE_EXE) needs Exchange 2007 or higher /// Room = 0x0007 } ================================================ FILE: MsgKit/Enums/RecurrencePatternCalendarType.cs ================================================ // // RecurrencePatternCalendarType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// An integer that specifies the type of calendar that is used. The acceptable values for the calendar type are listed /// in the following table. /// /// /// See https://msdn.microsoft.com/en-us/library/ee203303(v=exchg.80).aspx /// public enum RecurrencePatternCalendarType { /// /// The default value for the calendar type is Gregorian. /// If the value of the PatternType field is HjMonth, HjMonthNth, or HjMonthEnd and the value of the CalendarType field /// is Default, this recurrence uses the Hijri calendar. /// Default = 0x0000, /// /// Gregorian (localized) calendar /// CAL_GREGORIAN = 0x0001, /// /// Gregorian (U.S.) calendar /// CAL_GREGORIAN_US = 0x0002, /// /// Japanese Emperor era calendar /// CAL_JAPAN = 0x0003, /// /// Taiwan calendar /// CAL_TAIWAN = 0x0004, /// /// Korean Tangun era calendar /// CAL_KOREA = 0x0005, /// /// Hijri (Arabic Lunar) calendar /// CAL_HIJRI = 0x0006, /// /// Thai calendar /// CAL_THAI = 0x0007, /// /// Hebrew lunar calendar /// CAL_HEBREW = 0x0008, /// /// Gregorian Middle East French calendar /// CAL_GREGORIAN_ME_FRENCH = 0x0009, /// /// Gregorian Arabic calendar /// CAL_GREGORIAN_ARABIC = 0x000A, /// /// Gregorian transliterated English calendar /// CAL_GREGORIAN_XLIT_ENGLISH = 0x000B, /// /// Gregorian transliterated French calendar /// CAL_GREGORIAN_XLIT_FRENCH = 0x000C, /// /// Japanese lunar calendar /// CAL_LUNAR_JAPANESE = 0x000E, /// /// Chinese lunar calendar /// CAL_CHINESE_LUNAR = 0x000F, /// /// Saka era calendar /// CAL_SAKA = 0x0010, /// /// Lunar ETO Chinese calendar /// CAL_LUNAR_ETO_CHN = 0x0011, /// /// Lunar ETO Korean calendar /// CAL_LUNAR_ETO_KOR = 0x0012, /// /// Lunar Rokuyou calendar /// CAL_LUNAR_ROKUYOU = 0x0013, /// /// Korean lunar calendar /// CAL_LUNAR_KOREAN = 0x0014, /// /// Um Al Qura calendar /// CAL_UMALQURA = 0x0017 } ================================================ FILE: MsgKit/Enums/RecurrencePatternFirstDOWDay.cs ================================================ // // RecurrencePatternFirstDOWDay.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // // ReSharper disable InconsistentNaming namespace MsgKit.Enums; /// /// An integer that specifies the day on which the calendar week begins. The default value is Sunday (0x00000000). /// This field MUST be set to one of the values listed in the following table. /// /// /// See https://msdn.microsoft.com/en-us/library/ee203303(v=exchg.80).aspx /// public enum RecurrencePatternFirstDOWDay { /// /// Sunday /// Sunday = 0x00000000, /// /// Monday /// Monday = 0x00000001, /// /// Tuesday /// Tuesday = 0x00000002, /// /// Wednesday /// Wednesday = 0x00000003, /// /// Thursday /// Thursday = 0x00000004, /// /// Friday /// Friday = 0x00000005, /// /// Saterday /// Saturday = 0x00000006 } ================================================ FILE: MsgKit/Enums/RecurrencePatternFrequency.cs ================================================ // // RecurrencePatternFirstDateTimeFrequency.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// The value and meaning of the FirstDateTime field for each type of recurrence frequency are specified in the /// following table. For details about how the value is calculated, see section 2.2.1.44.1.1. /// /// /// See https://msdn.microsoft.com/en-us/library/ee203303(v=exchg.80).aspx /// public enum RecurrencePatternFrequency { /// /// Daily /// Daily, /// /// Weelky /// Weekly, /// /// Monthly /// Monthly } ================================================ FILE: MsgKit/Enums/RecurrencePatternPatternType.cs ================================================ // // RecurrencePatternPatternType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// PatternType (2 bytes): An integer that specifies the type of recurrence pattern. The valid recurrence pattern types /// are listed in the following table. /// /// /// See https://msdn.microsoft.com/en-us/library/ee203303(v=exchg.80).aspx /// public enum RecurrencePatternPatternType { /// /// The event has a daily recurrence. /// Day = 0x0000, /// /// The event has a weekly recurrence. /// Week = 0x0001, /// /// The event has a monthly recurrence. /// Month = 0x0002, /// /// The event has a month-end recurrence. /// MonthEnd = 0x0004, /// /// The event has an every nth month pattern. /// MonthNth = 0x0003, /// /// The event has a monthly recurrence in the Hijri calendar. For this value in the PatternType field, the value of the /// CalendarType field MUST be set to 0x0000. /// HjMonth = 0x0000A, /// /// The event has an every nth month pattern in the Hijri calendar. For this value in the PatternType field, the value /// of the CalendarType field MUST be set to 0x0000. /// HjMonthNth = 0x000B, /// /// The event has a month end recurrence in the Hijri calendar. For this value in the PatternType field, the value of /// the CalendarType field MUST be set to 0x0000. /// HjMonthEnd = 0x000C } ================================================ FILE: MsgKit/Enums/RecurrencePatternRecurrenceRangeType.cs ================================================ // // RecurrencePatternRecurrenceRangeType.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// EndType (4 bytes): An integer that specifies the ending type for the recurrence. This field MUST be set to one of /// the values listed in the following table. /// /// /// See https://msdn.microsoft.com/en-us/library/ee203303(v=exchg.80).aspx /// public enum RecurrencePatternRecurrenceRangeType { /// /// End after date /// EndAfterDate = 0x00002021, /// /// End after N occurrences /// EndAfterNoccurences = 0x00002022, /// /// Never end /// NeverEnd = 0x00002023 } ================================================ FILE: MsgKit/Enums/StoreSupportMask.cs ================================================ // // RecipientType.cs // // Author: RecipientRowDisplayType and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; // ReSharper disable InconsistentNaming namespace MsgKit.Enums; internal class StoreSupportMaskConst { public const StoreSupportMask StoreSupportMask = Enums.StoreSupportMask.STORE_ATTACH_OK | //StoreSupportMask.STORE_CATEGORIZE_OK | Enums.StoreSupportMask.STORE_CREATE_OK | //StoreSupportMask.STORE_ENTRYID_UNIQUE | Enums.StoreSupportMask.STORE_MODIFY_OK | //StoreSupportMask.STORE_MV_PROPS_OK | //StoreSupportMask.STORE_OLE_OK | //StoreSupportMask.STORE_RTF_OK | Enums.StoreSupportMask.STORE_HTML_OK | Enums.StoreSupportMask.STORE_UNICODE_OK; } /// /// This property discloses the capabilities of a message store to client applications planning to send it a message. /// The flags can facilitate decisions by a client or another store, such as whether to send PR_BODY (PidTagBody) or /// only (PidTagRtfCompressed). A client should never set /// an attempt returns MAPI_E_COMPUTED. /// [Flags] internal enum StoreSupportMask : uint { /// /// The message store supports properties containing ANSI (8-bit) characters. /// STORE_ANSI_OK = 0x00020000, /// /// The message store supports attachments (OLE or non-OLE) to messages. /// STORE_ATTACH_OK = 0x00000020, /// /// The message store supports categorized views of tables. /// STORE_CATEGORIZE_OK = 0x00000400, /// /// The message store supports creation of new messages. /// STORE_CREATE_OK = 0x00000010, /// /// Entry identifiers for the objects in the message store are unique, that is, never reused during the life of the /// store. /// STORE_ENTRYID_UNIQUE = 0x00000001, /// /// The message store supports HTML messages, stored in the (PidTagBodyHtml) /// property. Note that STORE_HTML_OK is not defined in versions of MAPIDEFS.H that are included with Microsoft Exchange /// 2000 Server and earlier. If your development environment uses a MAPIDEFS.H file that does not include STORE_HTML_OK, /// use the value 0x00010000 instead. /// STORE_HTML_OK = 0x00010000, /// /// In a wrapped PST store, indicates that when a new message arrives at the store, the store does rules and spam /// filter processing on the message separately. The store calls IMAPISupport::Notify, setting fnevNewMail in the /// NOTIFICATION structure that is passed as a parameter, and then passes the details of the new message to the /// listening client. Subsequently, when the listening client receives the notification, it does not process rules on /// the message. /// STORE_ITEMPROC = 0x00200000, /// /// This flag is reserved and should not be used. /// STORE_LOCALSTORE = 0x00080000, /// /// The message store supports modification of its existing messages. /// STORE_MODIFY_OK = 0x00000008, /// /// The message store supports multivalued properties, guarantees the stability of value order in a multivalued /// property throughout a save operation, and supports instantiation of multivalued properties in tables. /// STORE_MV_PROPS_OK = 0x00000200, /// /// The message store supports notifications. /// STORE_NOTIFY_OK = 0x00000100, /// /// The message store supports OLE attachments. The OLE data is accessible through an IStorage interface, such as that /// available through the PR_ATTACH_DATA_OBJ (PidTagAttachDataObject) property /// STORE_OLE_OK = 0x00000040, /// /// The folders in this store are public (multi-user), not private (possibly multi-instance but not multi-user). /// STORE_PUBLIC_FOLDERS = 0x00004000, /// /// The MAPI Protocol Handler will not crawl the store, and the store is responsible to push any changes through /// notifications to the indexer to have messages indexed. /// STORE_PUSHER_OK = 0x00800000, /// /// All interfaces for the message store have a read-only access level. /// STORE_READONLY = 0x00000002, /// /// The message store supports restrictions. /// STORE_RESTRICTION_OK = 0x00001000, /// /// The message store supports Rich Text Format (RTF) messages, usually compressed, and the store itself keeps /// and synchronized. /// STORE_RTF_OK = 0x00000800, /// /// The message store supports search-results folders. /// STORE_SEARCH_OK = 0x00000004, /// /// The message store supports sorting views of tables. /// STORE_SORT_OK = 0x00002000, /// /// The message store supports marking a message for submission. /// STORE_SUBMIT_OK = 0x00000080, /// /// The message store supports storage of RTF messages in uncompressed form. An uncompressed RTF stream is identified /// by the value dwMagicUncompressedRTF in the stream header. The dwMagicUncompressedRTF value is defined in the /// RTFLIB.H file /// STORE_UNCOMPRESSED_RTF = 0x00008000, /// /// The message store supports properties containing Unicode characters. /// STORE_UNICODE_OK = 0x00040000 } ================================================ FILE: MsgKit/Enums/TaskAcceptanceState.cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/cc839689.aspx /// public enum TaskAcceptanceState : uint { /// /// The task is not assigned. /// NotAssigned = 0x00000000, /// /// The task’s acceptance status is unknown. /// Unknow = 0x00000001, /// /// The task assignee accepted the task. This value is set when the client processes a task acceptance. /// Accepted = 0x00000002, /// /// The task assignee rejected the task. This value is set when the client processes a task rejection. /// Refused = 0x00000003 } ================================================ FILE: MsgKit/Enums/TaskHistory.cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/ee160354(v=EXCHG.80).aspx /// public enum TaskHistory : uint { /// /// No changes were made. /// NoChange = 0x00000000, /// /// The task assignee accepted this Task object. /// Accepted = 0x00000001, /// /// The task assignee rejected this Task object. /// Rejected = 0x00000002, /// /// Another property was changed. /// Modified = 0x00000003, /// /// The PidLidTaskDueDate property(section 2.2.2.2.5) changed. /// DueDateModified = 0x00000004, /// /// The Task object has been assigned to a task assignee. /// Assigned = 0x00000005 } ================================================ FILE: MsgKit/Enums/TaskMode.cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/ee178286(v=exchg.80).aspx /// public enum TaskMode : uint { /// /// The Task object is not assigned. /// NotAssigned = 0, /// /// The Task object is embedded in a task request. /// Requests = 1, /// /// The Task object has been accepted by the task assignee. /// Accepted = 2, /// /// The Task object was rejected by the task assignee. /// Rejected = 3, /// /// The Task object is embedded in a task update. /// Update = 4, /// /// The Task object was assigned to the task assigner (self-delegation). /// SelfDelegation = 5 } ================================================ FILE: MsgKit/Enums/TaskMultipleRecipients .cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/ee218493(v=exchg.80).aspx /// public enum TaskMultipleRecipients : uint { /// /// The Task object has multiple primary recipients. /// Sent = 0x00000000, /// /// Although the "Sent" flag was not set, the client detected that the Task object has multiple primary recipients. /// Received = 0x00000001 } ================================================ FILE: MsgKit/Enums/TaskOwnership.cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/ee204243(v=EXCHG.80).aspx /// public enum TaskOwnership : uint { /// /// The Task object is not assigned. /// NotAssigned = 0x00000000, /// /// The Task object is the task assigner's copy of the Task object. /// Assigner = 0x00000001, /// /// The Task object is the task assignee's copy of the Task object. /// Assignee = 0x00000002 } ================================================ FILE: MsgKit/Enums/TaskState.cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/cc765590(v=office.12).aspx /// public enum TaskState : uint { /// /// This task was created to correspond to a task that was embedded in a task rejection but could not be found locally. /// NotFound = 0x00000000, /// /// The task is not assigned. /// NotAssigned = 0x00000001, /// /// The task is the task assignee’s copy of an assigned task. /// AssigneeCopy = 0x00000002, /// /// The task is the task assigner’s copy of an assigned task. /// AssignerCopy = 0x00000003, /// /// The task is the task assigner’s copy of a rejected task. /// AssignerCopyRejected = 0x00000004 } ================================================ FILE: MsgKit/Enums/TaskStatus.cs ================================================ // ReSharper disable InconsistentNaming // // TaskAcceptanceState.cs // // Author: Kees van Spelde and Nicolas Fournier // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Enums; /// /// Valid values for the property /// /// /// See https://msdn.microsoft.com/en-us/library/ee159828(v=exchg.80).aspx /// public enum TaskStatus : uint { /// /// The user has not started work on the Task object. If the property is set to this value, the value of the /// PidLidPercentComplete property (section 2.2.2.2.3) MUST be 0.0. /// NotStarted = 0x00000000, /// /// The user's work on this Task object is in progress. If the property is set to this value, the value of the /// PidLidPercentComplete property MUST be greater than 0.0 and less than 1.0. /// InProgress = 0x00000001, /// /// The user's work on this Task object is complete. If the property is set to this value, the value of the /// PidLidPercentComplete property MUST be 1.0, the value of the PidLidTaskDateCompleted property (section 2.2.2.2.9) /// MUST be the current date, and the value of the PidLidTaskComplete property (section 2.2.2.2.20) MUST be 0x01. /// Completed = 0x00000002, /// /// The user is waiting on somebody else. /// Waiting = 0x00000003, /// /// The user has deferred work on the Task object. /// Deferred = 0x00000004 } ================================================ FILE: MsgKit/Exceptions/MKAttachment.cs ================================================ // // MWAttachment.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Exceptions; /// /// Raised when an attachment exception occurs /// public class MKAttachment : Exception { internal MKAttachment() { } internal MKAttachment(string message) : base(message) { } internal MKAttachment(string message, Exception inner) : base(message, inner) { } } ================================================ FILE: MsgKit/Exceptions/MKAttachmentExists.cs ================================================ // // MWAttachmentExists.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Exceptions; /// /// Raised when an attachment with the same name already exists /// public class MKAttachmentExists : Exception { internal MKAttachmentExists() { } internal MKAttachmentExists(string message) : base(message) { } internal MKAttachmentExists(string message, Exception inner) : base(message, inner) { } } ================================================ FILE: MsgKit/Exceptions/MKInvalidProperty.cs ================================================ // // MWInvalidProperty.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Exceptions; /// /// Raised when a property is invalid /// public class MKInvalidProperty : Exception { internal MKInvalidProperty() { } internal MKInvalidProperty(string message) : base(message) { } internal MKInvalidProperty(string message, Exception inner) : base(message, inner) { } } ================================================ FILE: MsgKit/Exceptions/MKMessageSaved.cs ================================================ // // MKMessageSaved.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Exceptions; /// /// Raised when somebody tries to modify a mesage when it already has been saved /// public class MKMessageSaved : Exception { internal MKMessageSaved() { } internal MKMessageSaved(string message) : base(message) { } internal MKMessageSaved(string message, Exception inner) : base(message, inner) { } } ================================================ FILE: MsgKit/Exceptions/MKPropertyNotFound.cs ================================================ // // MWPropertyNotFound.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Exceptions; /// /// Raised when a property is not found /// public class MKPropertyNotFound : Exception { internal MKPropertyNotFound() { } internal MKPropertyNotFound(string message) : base(message) { } internal MKPropertyNotFound(string message, Exception inner) : base(message, inner) { } } ================================================ FILE: MsgKit/Helpers/Conversion.cs ================================================ // // Conversion.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace MsgKit.Helpers; /// /// This class contains conversion related helper methods /// internal static class Conversion { #region ObjectToByteArray /// /// Converts an object to an byte array /// /// The object to convert /// public static byte[] ObjectToByteArray(Object obj) { if (obj == null) return null; var binaryFormatter = new BinaryFormatter(); using (var memoryStream = new MemoryStream()) { binaryFormatter.Serialize(memoryStream, obj); return memoryStream.ToArray(); } } #endregion #region ByteArrayToObject /// /// Converts a byte array to an Object /// /// The byte array /// public static Object ByteArrayToObject(byte[] array) { using (var memmoryStream = new MemoryStream()) { var binaryFormatter = new BinaryFormatter(); memmoryStream.Write(array, 0, array.Length); memmoryStream.Seek(0, SeekOrigin.Begin); return binaryFormatter.Deserialize(memmoryStream); } } #endregion } ================================================ FILE: MsgKit/Helpers/Crc32Calculator.cs ================================================ // // Crc32Calculator.cs // // Author: Kees van Spelde and Travis Semple // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // namespace MsgKit.Helpers; /// /// This class is used to calculate CRC32. Of a byte buffer. /// internal class Crc32Calculator { #region Crc32Table private static readonly uint[] Crc32Table = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; #endregion #region CalculateCrc32 public static uint CalculateCrc32(byte[] buffer) { uint result = 0; foreach (var b in buffer) result = Crc32Table[(result ^ b) & 0xFF] ^ (result >> 8); return result; } #endregion } ================================================ FILE: MsgKit/Helpers/EmailAddress.cs ================================================ // // EmailAddress.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System.Text.RegularExpressions; namespace MsgKit.Helpers; /// /// This class contains E-mail related helper methods /// internal static class EmailAddress { #region IsEmailAddressValid /// /// Return true when the E-mail address is valid /// /// /// public static bool IsEmailAddressValid(string emailAddress) { if (string.IsNullOrEmpty(emailAddress)) return false; var regex = new Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", RegexOptions.IgnoreCase); var matches = regex.Matches(emailAddress); return matches.Count == 1; } #endregion #region RemoveSingleQuotes /// /// Removes trailing en ending single quotes from an E-mail address when they exist /// /// /// public static string RemoveSingleQuotes(string email) { if (string.IsNullOrEmpty(email)) return string.Empty; if (email.StartsWith("'")) email = email.Substring(1, email.Length - 1); if (email.EndsWith("'")) email = email.Substring(0, email.Length - 1); return email; } #endregion } ================================================ FILE: MsgKit/Helpers/Exception.cs ================================================ // // Exception.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; namespace MsgKit.Helpers; /// /// This class contains exception related helper methods /// internal static class Exception { #region GetInnerException /// /// Get the complete inner exception tree /// /// The exception object /// public static string GetInnerException(System.Exception e) { var exception = e.Message + Environment.NewLine; if (e.InnerException != null) exception += GetInnerException(e.InnerException); return exception; } #endregion } ================================================ FILE: MsgKit/Helpers/ExtensionMethods.cs ================================================ using OpenMcdf; namespace MsgKit.Helpers; internal static class ExtensionMethods { /// /// Gets the storage or creates it when it not exist /// /// /// The name of the storage /// internal static Storage GetStorage(this Storage storage, string name) { return storage.TryOpenStorage(name, out var st) ? st : storage.CreateStorage(name); } /// /// Gets the stream or creates it when it not exist /// /// /// The name of the storage /// internal static CfbStream GetStream(this Storage storage, string name) { return storage.TryOpenStream(name, out var st) ? st : storage.CreateStream(name); } } ================================================ FILE: MsgKit/Helpers/FileManager.cs ================================================ // // FileManager.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.Globalization; using System.IO; using System.Linq; namespace MsgKit.Helpers; /// /// This class contains file management functions that are not available in the .NET framework /// internal static class FileManager { #region Consts /// /// De maximale pad lengte in Windows /// private const int MaxPath = 248; /// /// De maximale lengte voor een bestandsnaam /// private const int MaxFileNameLength = 255; #endregion #region CheckForDirectorySeparator /// /// Check if there is a directory separator char at the end of the string and if not add it /// /// /// public static string CheckForDirectorySeparator(string line) { var separator = Path.DirectorySeparatorChar.ToString(); if (line.EndsWith(separator)) return line; return line + separator; } #endregion #region FileExistsMakeNew /// /// Checks if a file already exists and if so adds a number until the file is unique /// /// The file to check /// When true validation will be performed on the max path lengt /// /// /// Raised when no path or file name is given in the /// Raised when it is not possible to truncate the public static string FileExistsMakeNew(string fileName, bool validateLongFileName = true, int extraTruncateSize = -1) { var tempFileName = fileName; var fileNameWithoutExtension = GetFileNameWithoutExtension(fileName); var extension = GetExtension(fileName); var path = CheckForDirectorySeparator(GetDirectoryName(fileName)); if (fileNameWithoutExtension.Length + extension.Length > MaxFileNameLength) { fileNameWithoutExtension = fileNameWithoutExtension.Substring(0, MaxFileNameLength - extension.Length); tempFileName = path + fileName; } tempFileName = validateLongFileName ? ValidateLongFileName(tempFileName, extraTruncateSize) : tempFileName; var i = 2; while (File.Exists(tempFileName)) { tempFileName = path + fileNameWithoutExtension + "_" + i + extension; tempFileName = validateLongFileName ? ValidateLongFileName(tempFileName, extraTruncateSize) : tempFileName; i += 1; } return tempFileName; } #endregion #region RemoveInvalidCharsFromFileName /// /// Removes illegal filename characters /// /// /// public static string RemoveInvalidFileNameChars(string fileName) { if (string.IsNullOrEmpty(fileName)) return fileName; var result = Path.GetInvalidFileNameChars() .Aggregate(fileName, (current, c) => current.Replace(c.ToString(CultureInfo.InvariantCulture), "_")); result = result.Replace(",", string.Empty); return result; } #endregion #region ValidateLongFileName /// /// Validates the length of , when this is longer then /// 260 chars it will be truncated. /// zodat deze wel past /// /// The filename with path /// Optional extra truncate size, when not used the filename is truncated until it fits /// /// Raised when no path or file name is given in the /// Raised when it is not possible to truncate the public static string ValidateLongFileName(string fileName, int extraTruncateSize = -1) { var fileNameWithoutExtension = GetFileNameWithoutExtension(fileName); if (string.IsNullOrWhiteSpace(fileNameWithoutExtension)) throw new ArgumentException(@"No file name is given, e.g. c:\temp\temp.txt", nameof(fileName)); var extension = GetExtension(fileName); if (string.IsNullOrWhiteSpace(extension)) extension = string.Empty; var path = GetDirectoryName(fileName); if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException(@"No path is given, e.g. c:\temp\temp.txt", nameof(fileName)); path = CheckForDirectorySeparator(path); if (fileName.Length <= MaxPath) return fileName; var maxFileNameLength = MaxPath - path.Length - extension.Length; if (extraTruncateSize != -1) maxFileNameLength -= extraTruncateSize; if (maxFileNameLength < 1) throw new PathTooLongException("Unable the truncate the fileName '" + fileName + "', current size '" + fileName.Length + "'"); return path + fileNameWithoutExtension.Substring(0, maxFileNameLength) + extension; } #endregion #region GetExtension /// /// Returns the extension of the specified string /// /// The path of the file /// /// Raised when no path is given public static string GetExtension(string path) { if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("path"); var splittedPath = path.Split(Path.DirectorySeparatorChar); var fileName = splittedPath[splittedPath.Length - 1]; var index = fileName.LastIndexOf(".", StringComparison.Ordinal); return index == -1 ? string.Empty : fileName.Substring(fileName.LastIndexOf(".", StringComparison.Ordinal), fileName.Length - index); } #endregion #region GetFileNameWithoutExtension /// /// Returns the file name of the specified string without the extension /// /// The path of the file /// /// public static string GetFileNameWithoutExtension(string path) { if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException(@"No path given", nameof(path)); var splittedPath = path.Split(Path.DirectorySeparatorChar); var fileName = splittedPath[splittedPath.Length - 1]; return !fileName.Contains(".") ? fileName : fileName.Substring(0, fileName.LastIndexOf(".", StringComparison.Ordinal)); } #endregion #region GetDirectoryName /// /// Returns the directory information for the specified string /// /// The path of a file or directory /// public static string GetDirectoryName(string path) { //GetDirectoryName('C:\MyDir\MySubDir\myfile.ext') returns 'C:\MyDir\MySubDir' //GetDirectoryName('C:\MyDir\MySubDir') returns 'C:\MyDir' //GetDirectoryName('C:\MyDir\') returns 'C:\MyDir' //GetDirectoryName('C:\MyDir') returns 'C:\' //GetDirectoryName('C:\') returns '' var splittedPath = path.Split(Path.DirectorySeparatorChar); if (splittedPath.Length <= 1) return string.Empty; var result = splittedPath[0]; for (var i = 1; i < splittedPath.Length - 1; i++) result += Path.DirectorySeparatorChar + splittedPath[i]; return result; } #endregion } ================================================ FILE: MsgKit/Helpers/Mapi.cs ================================================ // // Mapi.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.Text; namespace MsgKit.Helpers; /// /// This class contains MAPI related helper methods /// internal static class Mapi { #region Fields private static byte[] _instanceKey; #endregion #region GenerateSearchKey /// /// A search key is used to compare the data in two objects. An object's search key is stored in its /// (PidTagSearchKey) property. Because a search key /// represents an object's data and not the object itself, two different objects with the same data can have the same /// search key. When an object is copied, for example, both the original object and its copy have the same data and the /// same search key. Messages and messaging users have search keys. The search key of a message is a unique identifier /// of the message's data. Message store providers furnish a message's /// property at message creation time.The search key of an address book entry is computed from its address type( /// (PidTagAddressType)) and address /// ( (PidTagEmailAddress)). If the address book entry is writable, /// its search key might not be available until the address type and address have been set by using the /// IMAPIProp::SetProps method and the entry has been saved by using the IMAPIProp::SaveChanges method.When these /// address properties change, it is possible for the corresponding search key not to be synchronized with the new /// values until the changes have been committed with a SaveChanges call. The value of an object's record key can be /// the same as or different than the value of its search key, depending on the service provider. Some service providers /// use the same value for an object's search key, record key, and entry identifier.Other service providers assign unique /// values for each of its objects identifiers. /// /// public static byte[] GenerateSearchKey(string addressType, string emailAddress) { var searchKey = addressType + emailAddress; return Encoding.Unicode.GetBytes(searchKey); } #endregion #region GenerateRecordKey /// /// A record key is used to compare two objects. Message store and address book objects must have record keys, which /// are stored in their (PidTagRecordKey) property. Because a record key /// identifies an object and not its data, every instance of an object has a unique record key. The scope of a record /// key for folders and messages is the message store. The scope for address book containers, messaging users, and /// distribution lists is the set of top-level containers provided by MAPI for use in the integrated address book. /// Record keys can be duplicated in another resource. For example, different messages in two different message stores /// can have the same record key. This is different from long-term entry identifiers; because long-term entry /// identifiers contain a reference to the service provider, they have a wider scope.A message store's record key is /// similar in scope to a long-term entry identifier; it should be unique across all message store providers. To ensure /// this uniqueness, message store providers typically set their record key to a value that is the combination of their /// (PidTagStoreProvider) property and an identifier that is unique to the /// message store. /// /// public static byte[] GenerateRecordKey() { var guid = Guid.NewGuid(); return guid.ToByteArray(); } #endregion #region GenerateInstanceKey /// /// This property is a binary value that uniquely identifies a row in a table view. It is a required column in most /// tables. If a row is included in two views, there are two different instance keys. The instance key of a row may /// differ each time the table is opened, but remains constant while the table is open. Rows added while a table is in /// use do not reuse an instance key that was previously used. /// message store. /// /// public static byte[] GenerateInstanceKey() { if (_instanceKey == null) { _instanceKey = new byte[4]; Buffer.BlockCopy(Guid.NewGuid().ToByteArray(), 0, _instanceKey, 0, 4); } return _instanceKey; } #endregion #region GenerateEntryId /// /// The PR_ENTRYID property contains a MAPI entry identifier used to open and edit properties of a particular MAPI /// object. /// /// /// The PR_ENTRYID property identifies an object for OpenEntry to instantiate and provides access to all of its /// properties through the appropriate derived interface of IMAPIProp. PR_ENTRYID is one of the base address properties /// for all messaging users. The PR_ENTRYID for CEMAPI always contains long-term identifiers.
/// - Required on folder objects
/// - Required on message store objects
/// - Required on status objects
/// - Changed in a copy operation
/// - Unique within entire world ///
/// public static byte[] GenerateEntryId() { return Encoding.Unicode.GetBytes(Guid.NewGuid().ToString()); } #endregion } ================================================ FILE: MsgKit/Helpers/MimeType.cs ================================================ using System; using System.Collections.Generic; namespace MsgKit.Helpers; /// /// A mapping of file name extensions to the corresponding MIME-type. /// /// /// A mapping of file name extensions to the corresponding MIME-type. /// public static class MimeTypes { #region Fields /// /// A dictionary of mimetypes /// // ReSharper disable once InconsistentNaming public static readonly Dictionary mimeTypes; #endregion #region Constructor static MimeTypes() { mimeTypes = new Dictionary(StringComparer.OrdinalIgnoreCase); mimeTypes.Add("323", "text/h323"); mimeTypes.Add("3dmf", "x-world/x-3dmf"); mimeTypes.Add("3dm", "x-world/x-3dmf"); mimeTypes.Add("3g2", "video/3gpp2"); mimeTypes.Add("3gp", "video/3gpp"); mimeTypes.Add("7z", "application/x-7z-compressed"); mimeTypes.Add("aab", "application/x-authorware-bin"); mimeTypes.Add("aac", "audio/aac"); mimeTypes.Add("aam", "application/x-authorware-map"); mimeTypes.Add("aas", "application/x-authorware-seg"); mimeTypes.Add("abc", "text/vnd.abc"); mimeTypes.Add("acgi", "text/html"); mimeTypes.Add("acx", "application/internet-property-stream"); mimeTypes.Add("afl", "video/animaflex"); mimeTypes.Add("ai", "application/postscript"); mimeTypes.Add("aif", "audio/aiff"); mimeTypes.Add("aifc", "audio/aiff"); mimeTypes.Add("aiff", "audio/aiff"); mimeTypes.Add("aim", "application/x-aim"); mimeTypes.Add("aip", "text/x-audiosoft-intra"); mimeTypes.Add("ani", "application/x-navi-animation"); mimeTypes.Add("aos", "application/x-nokia-9000-communicator-add-on-software"); mimeTypes.Add("appcache", "text/cache-manifest"); mimeTypes.Add("application", "application/x-ms-application"); mimeTypes.Add("aps", "application/mime"); mimeTypes.Add("art", "image/x-jg"); mimeTypes.Add("asf", "video/x-ms-asf"); mimeTypes.Add("asm", "text/x-asm"); mimeTypes.Add("asp", "text/asp"); mimeTypes.Add("asr", "video/x-ms-asf"); mimeTypes.Add("asx", "application/x-mplayer2"); mimeTypes.Add("atom", "application/atom+xml"); mimeTypes.Add("au", "audio/x-au"); mimeTypes.Add("avi", "video/avi"); mimeTypes.Add("avs", "video/avs-video"); mimeTypes.Add("axs", "application/olescript"); mimeTypes.Add("bas", "text/plain"); mimeTypes.Add("bcpio", "application/x-bcpio"); mimeTypes.Add("bin", "application/octet-stream"); mimeTypes.Add("bm", "image/bmp"); mimeTypes.Add("bmp", "image/bmp"); mimeTypes.Add("boo", "application/book"); mimeTypes.Add("book", "application/book"); mimeTypes.Add("boz", "application/x-bzip2"); mimeTypes.Add("bsh", "application/x-bsh"); mimeTypes.Add("bz2", "application/x-bzip2"); mimeTypes.Add("bz", "application/x-bzip"); mimeTypes.Add("cat", "application/vnd.ms-pki.seccat"); mimeTypes.Add("ccad", "application/clariscad"); mimeTypes.Add("cco", "application/x-cocoa"); mimeTypes.Add("cc", "text/plain"); mimeTypes.Add("cdf", "application/cdf"); mimeTypes.Add("cer", "application/pkix-cert"); mimeTypes.Add("cha", "application/x-chat"); mimeTypes.Add("chat", "application/x-chat"); mimeTypes.Add("class", "application/x-java-applet"); mimeTypes.Add("clp", "application/x-msclip"); mimeTypes.Add("cmx", "image/x-cmx"); mimeTypes.Add("cod", "image/cis-cod"); mimeTypes.Add("coffee", "text/x-coffeescript"); mimeTypes.Add("conf", "text/plain"); mimeTypes.Add("cpio", "application/x-cpio"); mimeTypes.Add("cpp", "text/plain"); mimeTypes.Add("cpt", "application/x-cpt"); mimeTypes.Add("crd", "application/x-mscardfile"); mimeTypes.Add("crl", "application/pkix-crl"); mimeTypes.Add("crt", "application/pkix-cert"); mimeTypes.Add("csh", "application/x-csh"); mimeTypes.Add("css", "text/css"); mimeTypes.Add("c", "text/plain"); mimeTypes.Add("c++", "text/plain"); mimeTypes.Add("cxx", "text/plain"); mimeTypes.Add("dart", "application/dart"); mimeTypes.Add("dcr", "application/x-director"); mimeTypes.Add("deb", "application/x-deb"); mimeTypes.Add("deepv", "application/x-deepv"); mimeTypes.Add("def", "text/plain"); mimeTypes.Add("deploy", "application/octet-stream"); mimeTypes.Add("der", "application/x-x509-ca-cert"); mimeTypes.Add("dib", "image/bmp"); mimeTypes.Add("dif", "video/x-dv"); mimeTypes.Add("dir", "application/x-director"); mimeTypes.Add("disco", "text/xml"); mimeTypes.Add("dll", "application/x-msdownload"); mimeTypes.Add("dl", "video/dl"); mimeTypes.Add("doc", "application/msword"); mimeTypes.Add("docm", "application/vnd.ms-word.document.macroEnabled.12"); mimeTypes.Add("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); mimeTypes.Add("dot", "application/msword"); mimeTypes.Add("dotm", "application/vnd.ms-word.template.macroEnabled.12"); mimeTypes.Add("dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"); mimeTypes.Add("dp", "application/commonground"); mimeTypes.Add("drw", "application/drafting"); mimeTypes.Add("dtd", "application/xml-dtd"); mimeTypes.Add("dvi", "application/x-dvi"); mimeTypes.Add("dv", "video/x-dv"); mimeTypes.Add("dwf", "drawing/x-dwf (old)"); mimeTypes.Add("dwg", "application/acad"); mimeTypes.Add("dxf", "application/dxf"); mimeTypes.Add("dxr", "application/x-director"); mimeTypes.Add("elc", "application/x-elc"); mimeTypes.Add("el", "text/x-script.elisp"); mimeTypes.Add("eml", "message/rfc822"); mimeTypes.Add("eot", "application/vnd.bw-fontobject"); mimeTypes.Add("eps", "application/postscript"); mimeTypes.Add("es", "application/x-esrehber"); mimeTypes.Add("etx", "text/x-setext"); mimeTypes.Add("evy", "application/envoy"); mimeTypes.Add("exe", "application/octet-stream"); mimeTypes.Add("f77", "text/plain"); mimeTypes.Add("f90", "text/plain"); mimeTypes.Add("fdf", "application/vnd.fdf"); mimeTypes.Add("fif", "image/fif"); mimeTypes.Add("flac", "audio/x-flac"); mimeTypes.Add("fli", "video/fli"); mimeTypes.Add("flo", "image/florian"); mimeTypes.Add("flr", "x-world/x-vrml"); mimeTypes.Add("flx", "text/vnd.fmi.flexstor"); mimeTypes.Add("fmf", "video/x-atomic3d-feature"); mimeTypes.Add("for", "text/plain"); mimeTypes.Add("fpx", "image/vnd.fpx"); mimeTypes.Add("frl", "application/freeloader"); mimeTypes.Add("f", "text/plain"); mimeTypes.Add("funk", "audio/make"); mimeTypes.Add("g3", "image/g3fax"); mimeTypes.Add("gif", "image/gif"); mimeTypes.Add("gl", "video/gl"); mimeTypes.Add("gsd", "audio/x-gsm"); mimeTypes.Add("gsm", "audio/x-gsm"); mimeTypes.Add("gsp", "application/x-gsp"); mimeTypes.Add("gss", "application/x-gss"); mimeTypes.Add("gtar", "application/x-gtar"); mimeTypes.Add("g", "text/plain"); mimeTypes.Add("gz", "application/x-gzip"); mimeTypes.Add("gzip", "application/x-gzip"); mimeTypes.Add("hdf", "application/x-hdf"); mimeTypes.Add("help", "application/x-helpfile"); mimeTypes.Add("hgl", "application/vnd.hp-HPGL"); mimeTypes.Add("hh", "text/plain"); mimeTypes.Add("hlb", "text/x-script"); mimeTypes.Add("hlp", "application/x-helpfile"); mimeTypes.Add("hpg", "application/vnd.hp-HPGL"); mimeTypes.Add("hpgl", "application/vnd.hp-HPGL"); mimeTypes.Add("hqx", "application/binhex"); mimeTypes.Add("hta", "application/hta"); mimeTypes.Add("htc", "text/x-component"); mimeTypes.Add("h", "text/plain"); mimeTypes.Add("htmls", "text/html"); mimeTypes.Add("html", "text/html"); mimeTypes.Add("htm", "text/html"); mimeTypes.Add("htt", "text/webviewhtml"); mimeTypes.Add("htx", "text/html"); mimeTypes.Add("ice", "x-conference/x-cooltalk"); mimeTypes.Add("ico", "image/x-icon"); mimeTypes.Add("ics", "text/calendar"); mimeTypes.Add("idc", "text/plain"); mimeTypes.Add("ief", "image/ief"); mimeTypes.Add("iefs", "image/ief"); mimeTypes.Add("iges", "application/iges"); mimeTypes.Add("igs", "application/iges"); mimeTypes.Add("iii", "application/x-iphone"); mimeTypes.Add("ima", "application/x-ima"); mimeTypes.Add("imap", "application/x-httpd-imap"); mimeTypes.Add("inf", "application/inf"); mimeTypes.Add("ins", "application/x-internett-signup"); mimeTypes.Add("ip", "application/x-ip2"); mimeTypes.Add("isp", "application/x-internet-signup"); mimeTypes.Add("isu", "video/x-isvideo"); mimeTypes.Add("it", "audio/it"); mimeTypes.Add("iv", "application/x-inventor"); mimeTypes.Add("ivf", "video/x-ivf"); mimeTypes.Add("ivr", "i-world/i-vrml"); mimeTypes.Add("ivy", "application/x-livescreen"); mimeTypes.Add("jam", "audio/x-jam"); mimeTypes.Add("jar", "application/java-archive"); mimeTypes.Add("java", "text/plain"); mimeTypes.Add("jav", "text/plain"); mimeTypes.Add("jcm", "application/x-java-commerce"); mimeTypes.Add("jfif", "image/jpeg"); mimeTypes.Add("jfif-tbnl", "image/jpeg"); mimeTypes.Add("jpeg", "image/jpeg"); mimeTypes.Add("jpe", "image/jpeg"); mimeTypes.Add("jpg", "image/jpeg"); mimeTypes.Add("jps", "image/x-jps"); mimeTypes.Add("js", "application/javascript"); mimeTypes.Add("json", "application/json"); mimeTypes.Add("jut", "image/jutvision"); mimeTypes.Add("kar", "audio/midi"); mimeTypes.Add("ksh", "text/x-script.ksh"); mimeTypes.Add("la", "audio/nspaudio"); mimeTypes.Add("lam", "audio/x-liveaudio"); mimeTypes.Add("latex", "application/x-latex"); mimeTypes.Add("list", "text/plain"); mimeTypes.Add("lma", "audio/nspaudio"); mimeTypes.Add("log", "text/plain"); mimeTypes.Add("lsp", "application/x-lisp"); mimeTypes.Add("lst", "text/plain"); mimeTypes.Add("lsx", "text/x-la-asf"); mimeTypes.Add("ltx", "application/x-latex"); mimeTypes.Add("m13", "application/x-msmediaview"); mimeTypes.Add("m14", "application/x-msmediaview"); mimeTypes.Add("m1v", "video/mpeg"); mimeTypes.Add("m2a", "audio/mpeg"); mimeTypes.Add("m2v", "video/mpeg"); mimeTypes.Add("m3u", "audio/x-mpequrl"); mimeTypes.Add("m4a", "audio/mp4"); mimeTypes.Add("m4v", "video/mp4"); mimeTypes.Add("man", "application/x-troff-man"); mimeTypes.Add("manifest", "application/x-ms-manifest"); mimeTypes.Add("map", "application/x-navimap"); mimeTypes.Add("mar", "text/plain"); mimeTypes.Add("mbd", "application/mbedlet"); mimeTypes.Add("mc$", "application/x-magic-cap-package-1.0"); mimeTypes.Add("mcd", "application/mcad"); mimeTypes.Add("mcf", "image/vasa"); mimeTypes.Add("mcp", "application/netmc"); mimeTypes.Add("mdb", "application/x-msaccess"); mimeTypes.Add("mesh", "model/mesh"); mimeTypes.Add("me", "application/x-troff-me"); mimeTypes.Add("mid", "audio/midi"); mimeTypes.Add("midi", "audio/midi"); mimeTypes.Add("mif", "application/x-mif"); mimeTypes.Add("mjf", "audio/x-vnd.AudioExplosion.MjuiceMediaFile"); mimeTypes.Add("mjpg", "video/x-motion-jpeg"); mimeTypes.Add("mm", "application/base64"); mimeTypes.Add("mme", "application/base64"); mimeTypes.Add("mny", "application/x-msmoney"); mimeTypes.Add("mod", "audio/mod"); mimeTypes.Add("mov", "video/quicktime"); mimeTypes.Add("movie", "video/x-sgi-movie"); mimeTypes.Add("mp2", "video/mpeg"); mimeTypes.Add("mp3", "audio/mpeg"); mimeTypes.Add("mp4", "video/mp4"); mimeTypes.Add("mp4a", "audio/mp4"); mimeTypes.Add("mp4v", "video/mp4"); mimeTypes.Add("mpa", "audio/mpeg"); mimeTypes.Add("mpc", "application/x-project"); mimeTypes.Add("mpeg", "video/mpeg"); mimeTypes.Add("mpe", "video/mpeg"); mimeTypes.Add("mpga", "audio/mpeg"); mimeTypes.Add("mpg", "video/mpeg"); mimeTypes.Add("mpp", "application/vnd.ms-project"); mimeTypes.Add("mpt", "application/x-project"); mimeTypes.Add("mpv2", "video/mpeg"); mimeTypes.Add("mpv", "application/x-project"); mimeTypes.Add("mpx", "application/x-project"); mimeTypes.Add("mrc", "application/marc"); mimeTypes.Add("ms", "application/x-troff-ms"); mimeTypes.Add("msh", "model/mesh"); mimeTypes.Add("m", "text/plain"); mimeTypes.Add("mvb", "application/x-msmediaview"); mimeTypes.Add("mv", "video/x-sgi-movie"); mimeTypes.Add("my", "audio/make"); mimeTypes.Add("mzz", "application/x-vnd.AudioExplosion.mzz"); mimeTypes.Add("nap", "image/naplps"); mimeTypes.Add("naplps", "image/naplps"); mimeTypes.Add("nc", "application/x-netcdf"); mimeTypes.Add("ncm", "application/vnd.nokia.configuration-message"); mimeTypes.Add("niff", "image/x-niff"); mimeTypes.Add("nif", "image/x-niff"); mimeTypes.Add("nix", "application/x-mix-transfer"); mimeTypes.Add("nsc", "application/x-conference"); mimeTypes.Add("nvd", "application/x-navidoc"); mimeTypes.Add("nws", "message/rfc822"); mimeTypes.Add("oda", "application/oda"); mimeTypes.Add("ods", "application/oleobject"); mimeTypes.Add("oga", "audio/ogg"); mimeTypes.Add("ogg", "audio/ogg"); mimeTypes.Add("ogv", "video/ogg"); mimeTypes.Add("ogx", "application/ogg"); mimeTypes.Add("omc", "application/x-omc"); mimeTypes.Add("omcd", "application/x-omcdatamaker"); mimeTypes.Add("omcr", "application/x-omcregerator"); mimeTypes.Add("opus", "audio/ogg"); mimeTypes.Add("oxps", "application/oxps"); mimeTypes.Add("p10", "application/pkcs10"); mimeTypes.Add("p12", "application/pkcs-12"); mimeTypes.Add("p7a", "application/x-pkcs7-signature"); mimeTypes.Add("p7b", "application/x-pkcs7-certificates"); mimeTypes.Add("p7c", "application/pkcs7-mime"); mimeTypes.Add("p7m", "application/pkcs7-mime"); mimeTypes.Add("p7r", "application/x-pkcs7-certreqresp"); mimeTypes.Add("p7s", "application/pkcs7-signature"); mimeTypes.Add("part", "application/pro_eng"); mimeTypes.Add("pas", "text/pascal"); mimeTypes.Add("pbm", "image/x-portable-bitmap"); mimeTypes.Add("pcl", "application/x-pcl"); mimeTypes.Add("pct", "image/x-pict"); mimeTypes.Add("pcx", "image/x-pcx"); mimeTypes.Add("pdb", "chemical/x-pdb"); mimeTypes.Add("pdf", "application/pdf"); mimeTypes.Add("pfunk", "audio/make"); mimeTypes.Add("pfx", "application/x-pkcs12"); mimeTypes.Add("pgm", "image/x-portable-graymap"); mimeTypes.Add("pic", "image/pict"); mimeTypes.Add("pict", "image/pict"); mimeTypes.Add("pkg", "application/x-newton-compatible-pkg"); mimeTypes.Add("pko", "application/vnd.ms-pki.pko"); mimeTypes.Add("pl", "text/plain"); mimeTypes.Add("plx", "application/x-PiXCLscript"); mimeTypes.Add("pm4", "application/x-pagemaker"); mimeTypes.Add("pm5", "application/x-pagemaker"); mimeTypes.Add("pma", "application/x-perfmon"); mimeTypes.Add("pmc", "application/x-perfmon"); mimeTypes.Add("pm", "image/x-xpixmap"); mimeTypes.Add("pml", "application/x-perfmon"); mimeTypes.Add("pmr", "application/x-perfmon"); mimeTypes.Add("pmw", "application/x-perfmon"); mimeTypes.Add("png", "image/png"); mimeTypes.Add("pnm", "application/x-portable-anymap"); mimeTypes.Add("pot", "application/vnd.ms-powerpoint"); mimeTypes.Add("potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"); mimeTypes.Add("potx", "application/vnd.openxmlformats-officedocument.presentationml.template"); mimeTypes.Add("pov", "model/x-pov"); mimeTypes.Add("ppa", "application/vnd.ms-powerpoint"); mimeTypes.Add("ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"); mimeTypes.Add("ppm", "image/x-portable-pixmap"); mimeTypes.Add("pps", "application/vnd.ms-powerpoint"); mimeTypes.Add("ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"); mimeTypes.Add("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"); mimeTypes.Add("ppt", "application/vnd.ms-powerpoint"); mimeTypes.Add("pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"); mimeTypes.Add("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); mimeTypes.Add("ppz", "application/mspowerpoint"); mimeTypes.Add("pre", "application/x-freelance"); mimeTypes.Add("prf", "application/pics-rules"); mimeTypes.Add("prt", "application/pro_eng"); mimeTypes.Add("ps", "application/postscript"); mimeTypes.Add("p", "text/x-pascal"); mimeTypes.Add("pub", "application/x-mspublisher"); mimeTypes.Add("pvu", "paleovu/x-pv"); mimeTypes.Add("pwz", "application/vnd.ms-powerpoint"); mimeTypes.Add("pyc", "applicaiton/x-bytecode.python"); mimeTypes.Add("py", "text/x-script.phyton"); mimeTypes.Add("qcp", "audio/vnd.qcelp"); mimeTypes.Add("qd3d", "x-world/x-3dmf"); mimeTypes.Add("qd3", "x-world/x-3dmf"); mimeTypes.Add("qif", "image/x-quicktime"); mimeTypes.Add("qtc", "video/x-qtc"); mimeTypes.Add("qtif", "image/x-quicktime"); mimeTypes.Add("qti", "image/x-quicktime"); mimeTypes.Add("qt", "video/quicktime"); mimeTypes.Add("ra", "audio/x-pn-realaudio"); mimeTypes.Add("ram", "audio/x-pn-realaudio"); mimeTypes.Add("ras", "application/x-cmu-raster"); mimeTypes.Add("rast", "image/cmu-raster"); mimeTypes.Add("rexx", "text/x-script.rexx"); mimeTypes.Add("rf", "image/vnd.rn-realflash"); mimeTypes.Add("rgb", "image/x-rgb"); mimeTypes.Add("rm", "application/vnd.rn-realmedia"); mimeTypes.Add("rmi", "audio/mid"); mimeTypes.Add("rmm", "audio/x-pn-realaudio"); mimeTypes.Add("rmp", "audio/x-pn-realaudio"); mimeTypes.Add("rng", "application/ringing-tones"); mimeTypes.Add("rnx", "application/vnd.rn-realplayer"); mimeTypes.Add("roff", "application/x-troff"); mimeTypes.Add("rp", "image/vnd.rn-realpix"); mimeTypes.Add("rpm", "audio/x-pn-realaudio-plugin"); mimeTypes.Add("rss", "application/rss+xml"); mimeTypes.Add("rtf", "text/richtext"); mimeTypes.Add("rt", "text/richtext"); mimeTypes.Add("rtx", "text/richtext"); mimeTypes.Add("rv", "video/vnd.rn-realvideo"); mimeTypes.Add("s3m", "audio/s3m"); mimeTypes.Add("sbk", "application/x-tbook"); mimeTypes.Add("scd", "application/x-msschedule"); mimeTypes.Add("scm", "application/x-lotusscreencam"); mimeTypes.Add("sct", "text/scriptlet"); mimeTypes.Add("sdml", "text/plain"); mimeTypes.Add("sdp", "application/sdp"); mimeTypes.Add("sdr", "application/sounder"); mimeTypes.Add("sea", "application/sea"); mimeTypes.Add("set", "application/set"); mimeTypes.Add("setpay", "application/set-payment-initiation"); mimeTypes.Add("setreg", "application/set-registration-initiation"); mimeTypes.Add("sgml", "text/sgml"); mimeTypes.Add("sgm", "text/sgml"); mimeTypes.Add("shar", "application/x-bsh"); mimeTypes.Add("sh", "text/x-script.sh"); mimeTypes.Add("shtml", "text/html"); mimeTypes.Add("sid", "audio/x-psid"); mimeTypes.Add("silo", "model/mesh"); mimeTypes.Add("sit", "application/x-sit"); mimeTypes.Add("skd", "application/x-koan"); mimeTypes.Add("skm", "application/x-koan"); mimeTypes.Add("skp", "application/x-koan"); mimeTypes.Add("skt", "application/x-koan"); mimeTypes.Add("sl", "application/x-seelogo"); mimeTypes.Add("smi", "application/smil"); mimeTypes.Add("smil", "application/smil"); mimeTypes.Add("snd", "audio/basic"); mimeTypes.Add("sol", "application/solids"); mimeTypes.Add("spc", "application/x-pkcs7-certificates"); mimeTypes.Add("spl", "application/futuresplash"); mimeTypes.Add("spr", "application/x-sprite"); mimeTypes.Add("sprite", "application/x-sprite"); mimeTypes.Add("spx", "audio/ogg"); mimeTypes.Add("src", "application/x-wais-source"); mimeTypes.Add("ssi", "text/x-server-parsed-html"); mimeTypes.Add("ssm", "application/streamingmedia"); mimeTypes.Add("sst", "application/vnd.ms-pki.certstore"); mimeTypes.Add("step", "application/step"); mimeTypes.Add("s", "text/x-asm"); mimeTypes.Add("stl", "application/sla"); mimeTypes.Add("stm", "text/html"); mimeTypes.Add("stp", "application/step"); mimeTypes.Add("sv4cpio", "application/x-sv4cpio"); mimeTypes.Add("sv4crc", "application/x-sv4crc"); mimeTypes.Add("svf", "image/x-dwg"); mimeTypes.Add("svg", "image/svg+xml"); mimeTypes.Add("svr", "application/x-world"); mimeTypes.Add("swf", "application/x-shockwave-flash"); mimeTypes.Add("talk", "text/x-speech"); mimeTypes.Add("t", "application/x-troff"); mimeTypes.Add("tar", "application/x-tar"); mimeTypes.Add("tbk", "application/toolbook"); mimeTypes.Add("tcl", "text/x-script.tcl"); mimeTypes.Add("tcsh", "text/x-script.tcsh"); mimeTypes.Add("tex", "application/x-tex"); mimeTypes.Add("texi", "application/x-texinfo"); mimeTypes.Add("texinfo", "application/x-texinfo"); mimeTypes.Add("text", "text/plain"); mimeTypes.Add("tgz", "application/x-compressed"); mimeTypes.Add("tiff", "image/tiff"); mimeTypes.Add("tif", "image/tiff"); mimeTypes.Add("tr", "application/x-troff"); mimeTypes.Add("trm", "application/x-msterminal"); mimeTypes.Add("ts", "text/x-typescript"); mimeTypes.Add("tsi", "audio/tsp-audio"); mimeTypes.Add("tsp", "audio/tsplayer"); mimeTypes.Add("tsv", "text/tab-separated-values"); mimeTypes.Add("ttf", "application/x-font-ttf"); mimeTypes.Add("turbot", "image/florian"); mimeTypes.Add("txt", "text/plain"); mimeTypes.Add("uil", "text/x-uil"); mimeTypes.Add("uls", "text/iuls"); mimeTypes.Add("unis", "text/uri-list"); mimeTypes.Add("uni", "text/uri-list"); mimeTypes.Add("unv", "application/i-deas"); mimeTypes.Add("uris", "text/uri-list"); mimeTypes.Add("uri", "text/uri-list"); mimeTypes.Add("ustar", "multipart/x-ustar"); mimeTypes.Add("uue", "text/x-uuencode"); mimeTypes.Add("uu", "text/x-uuencode"); mimeTypes.Add("vcd", "application/x-cdlink"); mimeTypes.Add("vcf", "text/vcard"); mimeTypes.Add("vcard", "text/vcard"); mimeTypes.Add("vcs", "text/x-vCalendar"); mimeTypes.Add("vda", "application/vda"); mimeTypes.Add("vdo", "video/vdo"); mimeTypes.Add("vew", "application/groupwise"); mimeTypes.Add("vivo", "video/vivo"); mimeTypes.Add("viv", "video/vivo"); mimeTypes.Add("vmd", "application/vocaltec-media-desc"); mimeTypes.Add("vmf", "application/vocaltec-media-file"); mimeTypes.Add("voc", "audio/voc"); mimeTypes.Add("vos", "video/vosaic"); mimeTypes.Add("vox", "audio/voxware"); mimeTypes.Add("vqe", "audio/x-twinvq-plugin"); mimeTypes.Add("vqf", "audio/x-twinvq"); mimeTypes.Add("vql", "audio/x-twinvq-plugin"); mimeTypes.Add("vrml", "application/x-vrml"); mimeTypes.Add("vrt", "x-world/x-vrt"); mimeTypes.Add("vsd", "application/x-visio"); mimeTypes.Add("vst", "application/x-visio"); mimeTypes.Add("vsw", "application/x-visio"); mimeTypes.Add("w60", "application/wordperfect6.0"); mimeTypes.Add("w61", "application/wordperfect6.1"); mimeTypes.Add("w6w", "application/msword"); mimeTypes.Add("wav", "audio/wav"); mimeTypes.Add("wb1", "application/x-qpro"); mimeTypes.Add("wbmp", "image/vnd.wap.wbmp"); mimeTypes.Add("wcm", "application/vnd.ms-works"); mimeTypes.Add("wdb", "application/vnd.ms-works"); mimeTypes.Add("web", "application/vnd.xara"); mimeTypes.Add("webm", "video/webm"); mimeTypes.Add("wiz", "application/msword"); mimeTypes.Add("wk1", "application/x-123"); mimeTypes.Add("wks", "application/vnd.ms-works"); mimeTypes.Add("wmf", "windows/metafile"); mimeTypes.Add("wmlc", "application/vnd.wap.wmlc"); mimeTypes.Add("wmlsc", "application/vnd.wap.wmlscriptc"); mimeTypes.Add("wmls", "text/vnd.wap.wmlscript"); mimeTypes.Add("wml", "text/vnd.wap.wml"); mimeTypes.Add("wmp", "video/x-ms-wmp"); mimeTypes.Add("wmv", "video/x-ms-wmv"); mimeTypes.Add("wmx", "video/x-ms-wmx"); mimeTypes.Add("woff", "application/x-woff"); mimeTypes.Add("word", "application/msword"); mimeTypes.Add("wp5", "application/wordperfect"); mimeTypes.Add("wp6", "application/wordperfect"); mimeTypes.Add("wp", "application/wordperfect"); mimeTypes.Add("wpd", "application/wordperfect"); mimeTypes.Add("wps", "application/vnd.ms-works"); mimeTypes.Add("wq1", "application/x-lotus"); mimeTypes.Add("wri", "application/mswrite"); mimeTypes.Add("wrl", "application/x-world"); mimeTypes.Add("wrz", "model/vrml"); mimeTypes.Add("wsc", "text/scriplet"); mimeTypes.Add("wsdl", "text/xml"); mimeTypes.Add("wsrc", "application/x-wais-source"); mimeTypes.Add("wtk", "application/x-wintalk"); mimeTypes.Add("wvx", "video/x-ms-wvx"); mimeTypes.Add("x3d", "model/x3d+xml"); mimeTypes.Add("x3db", "model/x3d+fastinfoset"); mimeTypes.Add("x3dv", "model/x3d-vrml"); mimeTypes.Add("xaf", "x-world/x-vrml"); mimeTypes.Add("xaml", "application/xaml+xml"); mimeTypes.Add("xap", "application/x-silverlight-app"); mimeTypes.Add("xbap", "application/x-ms-xbap"); mimeTypes.Add("xbm", "image/x-xbitmap"); mimeTypes.Add("xdr", "video/x-amt-demorun"); mimeTypes.Add("xgz", "xgl/drawing"); mimeTypes.Add("xht", "application/xhtml+xml"); mimeTypes.Add("xhtml", "application/xhtml+xml"); mimeTypes.Add("xif", "image/vnd.xiff"); mimeTypes.Add("xla", "application/vnd.ms-excel"); mimeTypes.Add("xlam", "application/vnd.ms-excel.addin.macroEnabled.12"); mimeTypes.Add("xl", "application/excel"); mimeTypes.Add("xlb", "application/excel"); mimeTypes.Add("xlc", "application/excel"); mimeTypes.Add("xld", "application/excel"); mimeTypes.Add("xlk", "application/excel"); mimeTypes.Add("xll", "application/excel"); mimeTypes.Add("xlm", "application/excel"); mimeTypes.Add("xls", "application/vnd.ms-excel"); mimeTypes.Add("xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"); mimeTypes.Add("xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"); mimeTypes.Add("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); mimeTypes.Add("xlt", "application/vnd.ms-excel"); mimeTypes.Add("xltm", "application/vnd.ms-excel.template.macroEnabled.12"); mimeTypes.Add("xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"); mimeTypes.Add("xlv", "application/excel"); mimeTypes.Add("xlw", "application/excel"); mimeTypes.Add("xm", "audio/xm"); mimeTypes.Add("xml", "text/xml"); mimeTypes.Add("xmz", "xgl/movie"); mimeTypes.Add("xof", "x-world/x-vrml"); mimeTypes.Add("xpi", "application/x-xpinstall"); mimeTypes.Add("xpix", "application/x-vnd.ls-xpix"); mimeTypes.Add("xpm", "image/xpm"); mimeTypes.Add("xps", "application/vnd.ms-xpsdocument"); mimeTypes.Add("x-png", "image/png"); mimeTypes.Add("xsd", "text/xml"); mimeTypes.Add("xsl", "text/xml"); mimeTypes.Add("xslt", "text/xml"); mimeTypes.Add("xsr", "video/x-amt-showrun"); mimeTypes.Add("xwd", "image/x-xwd"); mimeTypes.Add("xyz", "chemical/x-pdb"); mimeTypes.Add("z", "application/x-compressed"); mimeTypes.Add("zip", "application/zip"); mimeTypes.Add("zsh", "text/x-script.zsh"); } #endregion #region GetMimeType /// /// Gets the MIME-type of the file. /// /// /// Gets the MIME-type of the file based on the file extension. /// /// The MIME-type. /// The file name. /// /// System.ArgumentNullException /// is null. /// public static string GetMimeType(string fileName) { if (fileName == null) throw new ArgumentNullException(nameof(fileName)); var dot = fileName.LastIndexOf('.'); string mimeType = null; if (dot != -1 && fileName.Length > dot + 1) mimeTypes.TryGetValue(fileName.Substring(dot + 1), out mimeType); return mimeType ?? "application/octet-stream"; } #endregion } ================================================ FILE: MsgKit/Helpers/Stream.cs ================================================ // // Stream.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using System.Text; namespace MsgKit.Helpers; /// /// This class contains stream related helper methods /// internal static class StreamUtility { #region ToByteArray /// /// Returns the stream as an byte array /// /// /// internal static byte[] ToByteArray(this Stream input) { using (var memoryStream = new MemoryStream()) { input.CopyTo(memoryStream); return memoryStream.ToArray(); } } #endregion #region Eos /// /// Returns true when the end of the has been reached /// /// /// internal static bool Eos(this BinaryReader binaryReader) { try { return binaryReader.BaseStream.Position >= binaryReader.BaseStream.Length; } catch (IOException) { return true; } } #endregion #region ReadLineAsBytes /// /// Read a line from the stream. /// A line is interpreted as all the bytes read until a CRLF or LF is encountered.
/// CRLF pair or LF is not included in the string. ///
/// The stream from which the line is to be read /// A line read from the stream returned as a byte array or if no bytes were readable from the stream /// If is public static byte[] ReadLineAsBytes(Stream stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); using (var memoryStream = new MemoryStream()) { while (true) { var justRead = stream.ReadByte(); if (justRead == -1 && memoryStream.Length > 0) break; // Check if we started at the end of the stream we read from // and we have not read anything from it yet if (justRead == -1 && memoryStream.Length == 0) return null; var readChar = (char)justRead; // Do not write \r or \n if (readChar != '\r' && readChar != '\n') memoryStream.WriteByte((byte)justRead); // Last point in CRLF pair if (readChar == '\n') break; } return memoryStream.ToArray(); } } #endregion #region ReadLineAsAscii /// /// Read a line from the stream. for more documentation. /// /// The stream to read from /// A line read from the stream or if nothing could be read from the stream /// If is public static string ReadLineAsAscii(Stream stream) { var readFromStream = ReadLineAsBytes(stream); return readFromStream != null ? Encoding.ASCII.GetString(readFromStream) : null; } #endregion } ================================================ FILE: MsgKit/Helpers/Strings.cs ================================================ // // Strings.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System.IO; using System.Text; // ReSharper disable UnusedMember.Global namespace MsgKit.Helpers; /// /// This class contains string related helper methods /// internal static class Strings { #region ReadNullTerminatedString /// /// Reads from the until a null terminated char is read /// /// /// /// public static string ReadNullTerminatedString(BinaryReader binaryReader, bool unicode = true) { return unicode ? ReadNullTerminatedUnicodeString(binaryReader) : ReadNullTerminatedAsciiString(binaryReader); } #endregion #region ReadNullTerminatedString /// /// Reads from the until a null terminated char is read /// /// The /// public static string ReadNullTerminatedAsciiString(BinaryReader binaryReader) { var result = new MemoryStream(); var b = binaryReader.ReadByte(); while (b != 0) { result.WriteByte(b); b = binaryReader.ReadByte(); } return Encoding.ASCII.GetString(result.ToArray()); } #endregion #region ReadNullTerminatedUnicodeString /// /// Reads from the until a null terminated char is read /// /// The /// public static string ReadNullTerminatedUnicodeString(BinaryReader binaryReader) { var result = new MemoryStream(); var b = binaryReader.ReadBytes(2); while (b[0] != 0 && b[1] != 0) { result.WriteByte(b[0]); result.WriteByte(b[2]); b = binaryReader.ReadBytes(2); } return Encoding.Unicode.GetString(result.ToArray()); } #endregion #region WriteNullTerminatedString /// /// Writes the given to the /// /// /// The string to write /// public static void WriteNullTerminatedString(BinaryWriter binaryWriter, string str, bool unicode = true) { if (unicode) WriteNullTerminatedUnicodeString(binaryWriter, str); else WriteNullTerminatedAsciiString(binaryWriter, str); } #endregion #region WriteNullTerminatedString /// /// Writes the given to the /// /// /// The string to write public static void WriteNullTerminatedAsciiString(BinaryWriter binaryWriter, string str) { var unicode = Encoding.Unicode.GetBytes(str); var ascii = Encoding.ASCII.GetString(unicode); binaryWriter.Write(ascii); binaryWriter.Write(0x00); } #endregion #region WriteNullTerminatedUnicodeString /// /// Writes the given to the /// /// /// The string to write public static void WriteNullTerminatedUnicodeString(BinaryWriter binaryWriter, string str) { var bytes = Encoding.Unicode.GetBytes(str); binaryWriter.Write(bytes); binaryWriter.Write(new byte[2]); } #endregion } ================================================ FILE: MsgKit/Message.cs ================================================ // // Message.cs // // Author: Kees van Spelde // // Copyright (c) 2013-2026 Kees van Spelde. (www.magic-sessions.com) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using MsgKit.Enums; using MsgKit.Exceptions; using MsgKit.Helpers; using MsgKit.Streams; using OpenMcdf; using Version = OpenMcdf.Version; // ReSharper disable UnusedMember.Global // ReSharper disable InconsistentNaming namespace MsgKit; /// /// The base class for all the different types of Outlook MSG files /// public class Message : IDisposable { #region Fields /// /// A flag to keep track if the message already has been saved /// private bool _saved; #endregion #region Properties /// /// The /// internal RootStorage CompoundFile { get; } /// /// The /// internal MessageClass Class = MessageClass.Unknown; /// /// Returns as a string that is written into the MSG file /// private string ClassAsString { get { switch (Class) { case MessageClass.Unknown: throw new ArgumentException("Class field is not set"); case MessageClass.IPM_Note: return "IPM.Note"; case MessageClass.IPM_Note_SMIME: return "IPM.Note.SMIME"; case MessageClass.IPM_Note_SMIME_MultipartSigned: return "IPM.Note.SMIME.MultipartSigned"; case MessageClass.IPM_Note_Receipt_SMIME: return "IPM.Note.Receipt.SMIME"; case MessageClass.IPM_Post: return "IPM.Post"; case MessageClass.IPM_Octel_Voice: return "IPM.Octel.Voice"; case MessageClass.IPM_Voicenotes: return "IPM.Voicenotes"; case MessageClass.IPM_Sharing: return "IPM.Sharing"; case MessageClass.REPORT_IPM_NOTE_NDR: return "REPORT.IPM.NOTE.NDR"; case MessageClass.REPORT_IPM_NOTE_DR: return "REPORT.IPM.NOTE.DR"; case MessageClass.REPORT_IPM_NOTE_DELAYED: return "REPORT.IPM.NOTE.DELAYED"; case MessageClass.REPORT_IPM_NOTE_IPNRN: return "*REPORT.IPM.NOTE.IPNRN"; case MessageClass.REPORT_IPM_NOTE_IPNNRN: return "*REPORT.IPM.NOTE.IPNNRN"; case MessageClass.REPORT_IPM_SCHEDULE_MEETING_REQUEST_NDR: return "REPORT.IPM.SCHEDULE. MEETING.REQUEST.NDR"; case MessageClass.REPORT_IPM_SCHEDULE_MEETING_RESP_POS_NDR: return "REPORT.IPM.SCHEDULE.MEETING.RESP.POS.NDR"; case MessageClass.REPORT_IPM_SCHEDULE_MEETING_RESP_TENT_NDR: return "REPORT.IPM.SCHEDULE.MEETING.RESP.TENT.NDR"; case MessageClass.REPORT_IPM_SCHEDULE_MEETING_CANCELED_NDR: return "REPORT.IPM.SCHEDULE.MEETING.CANCELED.NDR"; case MessageClass.REPORT_IPM_NOTE_SMIME_NDR: return "REPORT.IPM.NOTE.SMIME.NDR"; case MessageClass.REPORT_IPM_NOTE_SMIME_DR: return "*REPORT.IPM.NOTE.SMIME.DR"; case MessageClass.REPORT_IPM_NOTE_SMIME_MULTIPARTSIGNED_NDR: return "*REPORT.IPM.NOTE.SMIME.MULTIPARTSIGNED.NDR"; case MessageClass.REPORT_IPM_NOTE_SMIME_MULTIPARTSIGNED_DR: return "*REPORT.IPM.NOTE.SMIME.MULTIPARTSIGNED.DR"; case MessageClass.IPM_Appointment: return "IPM.Appointment"; case MessageClass.IPM_Task: return "IPM.Task"; case MessageClass.IPM_Contact: return "IPM.Contact"; default: throw new ArgumentOutOfRangeException(); } } } /// /// Contains a number that indicates which icon to use when you display a group /// of e-mail objects. Default set to /// /// /// This property, if it exists, is a hint to the client. The client may ignore the /// value of this property. /// public MessageIconIndex IconIndex { get; set; } /// /// The size of the message /// public long MessageSize { get; internal set; } /// /// The /// internal readonly TopLevelProperties TopLevelProperties; /// /// The /// internal readonly NamedProperties NamedProperties; #endregion #region Constructor /// /// Creates this object and sets all it's properties /// internal Message() { CompoundFile = RootStorage.CreateInMemory(Version.V3, StorageModeFlags.Transacted); // In the preceding figure, the "__nameid_version1.0" named property mapping storage contains the // three streams used to provide a mapping from property ID to property name // ("__substg1.0_00020102", "__substg1.0_00030102", and "__substg1.0_00040102") and various other // streams that provide a mapping from property names to property IDs. var nameIdStorage = CompoundFile.GetStorage(PropertyTags.NameIdStorage); using var entryStream = nameIdStorage.CreateStream(PropertyTags.EntryStream); entryStream.Write([], 0, 0); using var stringStream = nameIdStorage.CreateStream(PropertyTags.StringStream); stringStream.Write([], 0, 0); using var guidStream = nameIdStorage.CreateStream(PropertyTags.GuidStream); guidStream.Write([], 0, 0); TopLevelProperties = []; NamedProperties = new NamedProperties(TopLevelProperties); } #endregion #region Save private void Save() { TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_CLASS_W, ClassAsString); TopLevelProperties.WriteProperties(CompoundFile, MessageSize); NamedProperties.WriteProperties(CompoundFile); _saved = true; } /// /// Saves the message to the given /// /// internal void Save(string fileName) { Save(); CompoundFile.Commit(); CompoundFile.SwitchTo(fileName); } /// /// Saves the message to the given /// /// internal void Save(Stream stream) { Save(); CompoundFile.Commit(); var baseStreamPosition = CompoundFile.BaseStream.Position; CompoundFile.BaseStream.Position = 0; CompoundFile.BaseStream.CopyTo(stream); CompoundFile.BaseStream.Position = baseStreamPosition; } #endregion #region AddProperty /// /// Adds a custom property to the message or replaces it when it already exists /// /// /// The value of the property /// /// Raised when the message has already been saved with the Save method public void AddProperty(PropertyTags.PropertyTag property, object value, PropertyFlags flags = PropertyFlags.PROPATTR_WRITABLE) { if (_saved) throw new MKMessageSaved("The message can't be modified when it already has been saved"); TopLevelProperties.AddOrReplaceProperty(property, value, flags); } #endregion #region AddNamedProperty /// /// Adds a custom named property to the message or replaces it when it already exists /// /// /// The value of the property /// Raised when the message has already been saved with the Save method public void AddProperty(NamedPropertyTag namedProperty, object value) { if (_saved) throw new MKMessageSaved("The message can't be modified when it already has been saved"); NamedProperties.AddProperty(namedProperty, value); } #endregion #region Dispose /// /// Disposes this object and all its resources /// public void Dispose() { CompoundFile?.Dispose(); } #endregion } ================================================ FILE: MsgKit/Mime/Decode/Base64.cs ================================================ using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace MsgKit.Mime.Decode; /// /// Utility class for dealing with Base64 encoded strings /// internal static class Base64 { #region Decode /// /// Decodes a base64 encoded string into the bytes it describes /// /// The string to decode /// A byte array that the base64 string described public static byte[] Decode(string base64Encoded) { try { using (var memoryStream = new MemoryStream()) { base64Encoded = base64Encoded.Replace("\r\n", ""); base64Encoded = base64Encoded.Replace("\t", ""); base64Encoded = base64Encoded.Replace(" ", ""); var inputBytes = Encoding.ASCII.GetBytes(base64Encoded); using (var transform = new FromBase64Transform(FromBase64TransformMode.DoNotIgnoreWhiteSpaces)) { var outputBytes = new byte[transform.OutputBlockSize]; // Transform the data in chunks the size of InputBlockSize. const int inputBlockSize = 4; var currentOffset = 0; while (inputBytes.Length - currentOffset > inputBlockSize) { transform.TransformBlock(inputBytes, currentOffset, inputBlockSize, outputBytes, 0); currentOffset += inputBlockSize; memoryStream.Write(outputBytes, 0, transform.OutputBlockSize); } // Transform the final block of data. outputBytes = transform.TransformFinalBlock(inputBytes, currentOffset, inputBytes.Length - currentOffset); memoryStream.Write(outputBytes, 0, outputBytes.Length); } return memoryStream.ToArray(); } } catch (Exception) { return new byte[0]; } } /// /// Decodes a Base64 encoded string using a specified /// /// Source string to decode /// The encoding to use for the decoded byte array that describes /// A decoded string /// /// If or is /// /// /// If is not a valid base64 encoded string public static string Decode(string base64Encoded, Encoding encoding) { if (base64Encoded == null) throw new ArgumentNullException(nameof(base64Encoded)); if (encoding == null) throw new ArgumentNullException(nameof(encoding)); try { return encoding.GetString(Decode(base64Encoded)); } catch (FormatException) { return string.Empty; } } #endregion } ================================================ FILE: MsgKit/Mime/Decode/EncodedWord.cs ================================================ using System; using System.Text.RegularExpressions; namespace MsgKit.Mime.Decode; /// /// Utility class for dealing with encoded word strings
///
/// EncodedWord encoded strings are only in ASCII, but can embed information /// about characters in other character sets.
///
/// It is done by specifying the character set, an encoding that maps from ASCII to /// the correct bytes and the actual encoded string.
///
/// It is specified in a format that is best summarized by a BNF:
/// "=?" character_set "?" encoding "?" encoded-text "?="
///
/// /// =?ISO-8859-1?Q?=2D?= /// Here ISO-8859-1 is the character set.
/// Q is the encoding method (quoted-printable). B is also supported (Base 64).
/// The encoded text is the =2D part which is decoded to a space. ///
internal static class EncodedWord { #region Decode /// /// Decode text that is encoded with the encoding.
///
/// This method will decode any encoded-word found in the string.
/// All parts which is not encoded will not be touched.
///
/// From RFC 2047:
/// /// Generally, an "encoded-word" is a sequence of printable ASCII /// characters that begins with "=?", ends with "?=", and has two "?"s in /// between. It specifies a character set and an encoding method, and /// also includes the original text encoded as graphic ASCII characters, /// according to the rules for that encoding method. /// /// Example:
/// =?ISO-8859-1?q?this=20is=20some=20text?= other text here ///
/// /// See RFC 2047 section 2 "Syntax of encoded-words" /// for more details /// /// Source text. May be content which is not encoded. /// Decoded text /// If is public static string Decode(string encodedWords) { if (encodedWords == null) throw new ArgumentNullException(nameof(encodedWords)); // Notice that RFC2231 redefines the BNF to // encoded-word := "=?" charset ["*" language] "?" encoded-text "?=" // but no usage of this BNF have been spotted yet. It is here to // ease debugging if such a case is discovered. // This is the regex that should fit the BNF // RFC Says that NO WHITESPACE is allowed in this encoding, but there are examples // where whitespace is there, and therefore this regex allows for such. const string encodedWordRegex = @"\=\?(?\S+?)\?(?\w)\?(?.*?)\?\="; // \w Matches any word character including underscore. Equivalent to "[A-Za-z0-9_]". // \S Matches any nonwhite space character. Equivalent to "[^ \f\n\r\t\v]". // +? non-greedy equivalent to + // (?REGEX) is a named group with name NAME and regular expression REGEX // Any amount of linear-space-white between 'encoded-word's, // even if it includes a CRLF followed by one or more SPACEs, // is ignored for the purposes of display. // http://tools.ietf.org/html/rfc2047#page-12 // Define a regular expression that captures two encoded words with some whitespace between them const string replaceRegex = @"(?" + encodedWordRegex + @")\s+(?" + encodedWordRegex + ")"; // Then, find an occurrence of such an expression, but remove the whitespace in between when found // Need to be done twice for encodings such as "=?UTF-8?Q?a?= =?UTF-8?Q?b?= =?UTF-8?Q?c?=" // to be replaced correctly encodedWords = Regex.Replace(encodedWords, replaceRegex, "${first}${second}"); encodedWords = Regex.Replace(encodedWords, replaceRegex, "${first}${second}"); var decodedWords = encodedWords; var matches = Regex.Matches(encodedWords, encodedWordRegex); foreach (Match match in matches) { // If this match was not a success, we should not use it if (!match.Success) continue; var fullMatchValue = match.Value; var encodedText = match.Groups["Content"].Value; var encoding = match.Groups["Encoding"].Value; var charset = match.Groups["Charset"].Value; // Get the encoding which corresponds to the character set var charsetEncoding = EncodingFinder.FindEncoding(charset); // Store decoded text here when done string decodedText; // Encoding may also be written in lowercase switch (encoding.ToUpperInvariant()) { // RFC: // The "B" encoding is identical to the "BASE64" // encoding defined by RFC 2045. // http://tools.ietf.org/html/rfc2045#section-6.8 case "B": decodedText = Base64.Decode(encodedText, charsetEncoding); break; // RFC: // The "Q" encoding is similar to the "Quoted-Printable" content- // transfer-encoding defined in RFC 2045. // There are more details to this. Please check // http://tools.ietf.org/html/rfc2047#section-4.2 // case "Q": decodedText = QuotedPrintable.DecodeEncodedWord(encodedText, charsetEncoding); break; default: throw new ArgumentException("The encoding " + encoding + " was not recognized"); } // Replace our encoded value with our decoded value decodedWords = decodedWords.Replace(fullMatchValue, decodedText); } return decodedWords; } #endregion } ================================================ FILE: MsgKit/Mime/Decode/EncodingFinder.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Text; namespace MsgKit.Mime.Decode; /// /// Utility class used by OpenPop for mapping from a characterSet to an .
///
/// The functionality of the class can be altered by adding mappings /// using and by adding a .
///
/// Given a characterSet, it will try to find the Encoding as follows: /// /// /// /// If a mapping for the characterSet was added, use the specified Encoding from there. Mappings /// can be added using . /// /// /// /// /// Try to parse the characterSet and look it up using /// for codepages or for named encodings. /// /// /// /// /// If an encoding is not found yet, use the if defined. The /// is user defined. /// /// /// ///
public static class EncodingFinder { #region Constructor /// /// Initialize the EncodingFinder /// static EncodingFinder() { Reset(); } #endregion #region Reset /// /// Used to reset this static class to facilite isolated unit testing. /// internal static void Reset() { EncodingMap = new Dictionary(); FallbackDecoder = null; // Some emails incorrectly specify the encoding as utf8, but it should have been utf-8. AddMapping("utf8", Encoding.UTF8); AddMapping("binary", Encoding.ASCII); } #endregion #region FindEncoding /// /// Parses a character set into an encoding. /// /// The character set to parse /// An encoding which corresponds to the character set /// If is internal static Encoding FindEncoding(string characterSet) { if (characterSet == null) throw new ArgumentNullException(nameof(characterSet)); var charSetUpper = characterSet.ToUpperInvariant(); // Check if the characterSet is explicitly mapped to an encoding if (EncodingMap.ContainsKey(charSetUpper)) return EncodingMap[charSetUpper]; // Try to generally find the encoding try { if (!charSetUpper.Contains("WINDOWS") && !charSetUpper.Contains("CP")) return Encoding.GetEncoding(characterSet); // It seems the characterSet contains an codepage value, which we should use to parse the encoding charSetUpper = charSetUpper.Replace("CP", ""); // Remove cp charSetUpper = charSetUpper.Replace("WINDOWS", ""); // Remove windows charSetUpper = charSetUpper.Replace("-", ""); // Remove - which could be used as cp-1554 // Now we hope the only thing left in the characterSet is numbers. var codepageNumber = int.Parse(charSetUpper, CultureInfo.InvariantCulture); return Encoding.GetEncoding(codepageNumber); // It seems there is no codepage value in the characterSet. It must be a named encoding } catch (ArgumentException) { // The encoding could not be found generally. // Try to use the FallbackDecoder if it is defined. // Check if it is defined if (FallbackDecoder == null) throw; // It was not defined - throw catched exception // Use the FallbackDecoder var fallbackDecoderResult = FallbackDecoder(characterSet); // Check if the FallbackDecoder had a solution if (fallbackDecoderResult != null) return fallbackDecoderResult; // If no solution was found, throw catched exception throw; } } #endregion #region AddMapping /// /// Puts a mapping from to /// into the 's internal mapping Dictionary. /// /// The string that maps to the /// The that should be mapped from /// If is /// If is public static void AddMapping(string characterSet, Encoding encoding) { if (characterSet == null) throw new ArgumentNullException(nameof(characterSet)); if (encoding == null) throw new ArgumentNullException(nameof(encoding)); // Add the mapping using uppercase EncodingMap.Add(characterSet.ToUpperInvariant(), encoding); } #endregion #region Proprties /// /// Delegate that is used when the EncodingFinder is unable to find an encoding by /// using the or general code.
/// This is used as a last resort and can be used for setting a default encoding or /// for finding an encoding on runtime for some . ///
/// The character set to find an encoding for. /// An encoding for the or if none could be found. public delegate Encoding FallbackDecoderDelegate(string characterSet); /// /// Last resort decoder. /// public static FallbackDecoderDelegate FallbackDecoder { private get; set; } /// /// Mapping from charactersets to encodings. /// private static Dictionary EncodingMap { get; set; } #endregion } ================================================ FILE: MsgKit/Mime/Decode/QuotedPrintable.cs ================================================ using System; using System.IO; using System.Text; using System.Text.RegularExpressions; namespace MsgKit.Mime.Decode; /// /// Used for decoding Quoted-Printable text.
/// This is a robust implementation of a Quoted-Printable decoder defined in /// RFC 2045 and /// RFC 2047.
/// Every measurement has been taken to conform to the RFC. ///
internal static class QuotedPrintable { #region DecodeEncodedWord /// /// Decodes a Quoted-Printable string according to RFC 2047.
/// RFC 2047 is used for decoding Encoded-Word encoded strings. ///
/// Quoted-Printable encoded string /// Specifies which encoding the returned string will be in /// A decoded string in the correct encoding /// /// If or is /// /// public static string DecodeEncodedWord(string toDecode, Encoding encoding) { if (toDecode == null) throw new ArgumentNullException(nameof(toDecode)); if (encoding == null) throw new ArgumentNullException(nameof(encoding)); // Decode the QuotedPrintable string and return it return encoding.GetString(Rfc2047QuotedPrintableDecode(toDecode, true)); } #endregion #region DecodeContentTransferEncoding /// /// Decodes a Quoted-Printable string according to RFC 2045.
/// RFC 2045 specifies the decoding of a body encoded with Content-Transfer-Encoding of quoted-printable. ///
/// Quoted-Printable encoded string /// A decoded byte array that the Quoted-Printable encoded string described /// If is public static byte[] DecodeContentTransferEncoding(string toDecode) { if (toDecode == null) throw new ArgumentNullException(nameof(toDecode)); // Decode the QuotedPrintable string and return it return Rfc2047QuotedPrintableDecode(toDecode, false); } #endregion #region Rfc2047QuotedPrintableDecode /// /// This is the actual decoder. /// /// The string to be decoded from Quoted-Printable /// /// If , specifies that RFC 2047 quoted printable decoding is used.
/// This is for quoted-printable encoded words
///
/// If , specifies that RFC 2045 quoted printable decoding is used.
/// This is for quoted-printable Content-Transfer-Encoding /// /// A decoded byte array that was described by /// If is /// See RFC 2047 section 4.2 for RFC details private static byte[] Rfc2047QuotedPrintableDecode(string toDecode, bool encodedWordVariant) { if (toDecode == null) throw new ArgumentNullException(nameof(toDecode)); // Create a byte array builder which is roughly equivalent to a StringBuilder using (var byteArrayBuilder = new MemoryStream()) { // Remove illegal control characters toDecode = RemoveIllegalControlCharacters(toDecode); // Run through the whole string that needs to be decoded for (var i = 0; i < toDecode.Length; i++) { var currentChar = toDecode[i]; if (currentChar == '=') { // Check that there is at least two characters behind the equal sign if (toDecode.Length - i < 3) { // We are at the end of the toDecode string, but something is missing. Handle it the way RFC 2045 states WriteAllBytesToStream(byteArrayBuilder, DecodeEqualSignNotLongEnough(toDecode.Substring(i))); // Since it was the last part, we should stop parsing anymore break; } // Decode the Quoted-Printable part var quotedPrintablePart = toDecode.Substring(i, 3); WriteAllBytesToStream(byteArrayBuilder, DecodeEqualSign(quotedPrintablePart)); // We now consumed two extra characters. Go forward two extra characters i += 2; } else { // This character is not quoted printable hex encoded. // Could it be the _ character, which represents space // and are we using the encoded word variant of QuotedPrintable if (currentChar == '_' && encodedWordVariant) byteArrayBuilder.WriteByte(0x20); else byteArrayBuilder.WriteByte((byte)currentChar); } } return byteArrayBuilder.ToArray(); } } #endregion #region WriteAllBytesToStream /// /// Writes all bytes in a byte array to a stream /// /// The stream to write to /// The bytes to write to the private static void WriteAllBytesToStream(Stream stream, byte[] toWrite) { stream.Write(toWrite, 0, toWrite.Length); } #endregion #region RemoveIllegalControlCharacters /// /// RFC 2045 states about robustness:
/// /// Control characters other than TAB, or CR and LF as parts of CRLF pairs, /// must not appear. The same is true for octets with decimal values greater /// than 126. If found in incoming quoted-printable data by a decoder, a /// robust implementation might exclude them from the decoded data and warn /// the user that illegal characters were discovered. /// /// Control characters are defined in RFC 2396 as
/// control = US-ASCII coded characters 00-1F and 7F hexadecimal ///
/// String to be stripped from illegal control characters /// A string with no illegal control characters /// If is private static string RemoveIllegalControlCharacters(string input) { if (input == null) throw new ArgumentNullException(nameof(input)); // First we remove any \r or \n which is not part of a \r\n pair input = RemoveCarriageReturnAndNewLinewIfNotInPair(input); // Here only legal \r\n is left over // We now simply keep them, and the \t which is also allowed // \x0A = \n // \x0D = \r // \x09 = \t) return Regex.Replace(input, "[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]", ""); } #endregion #region RemoveCarriageReturnAndNewLinewIfNotInPair /// /// This method will remove any \r and \n which is not paired as \r\n /// /// String to remove lonely \r and \n's from /// A string without lonely \r and \n's /// If is private static string RemoveCarriageReturnAndNewLinewIfNotInPair(string input) { if (input == null) throw new ArgumentNullException(nameof(input)); // Use this for building up the new string. This is used for performance instead // of altering the input string each time a illegal token is found var newString = new StringBuilder(input.Length); for (var i = 0; i < input.Length; i++) // There is a character after it // Check for lonely \r // There is a lonely \r if it is the last character in the input or if there // is no \n following it if (input[i] == '\r' && (i + 1 >= input.Length || input[i + 1] != '\n')) { // Illegal token \r found. Do not add it to the new string // Check for lonely \n // There is a lonely \n if \n is the first character or if there // is no \r in front of it } else if (input[i] == '\n' && (i - 1 < 0 || input[i - 1] != '\r')) { // Illegal token \n found. Do not add it to the new string } else { // No illegal tokens found. Simply insert the character we are at // in our new string newString.Append(input[i]); } return newString.ToString(); } #endregion #region DecodeEqualSignNotLongEnough /// /// RFC 2045 says that a robust implementation should handle:
/// /// An "=" cannot be the ultimate or penultimate character in an encoded /// object. This could be handled as in case (2) above. /// /// Case (2) is:
/// /// An "=" followed by a character that is neither a /// hexadecimal digit (including "abcdef") nor the CR character of a CRLF pair /// is illegal. This case can be the result of US-ASCII text having been /// included in a quoted-printable part of a message without itself having /// been subjected to quoted-printable encoding. A reasonable approach by a /// robust implementation might be to include the "=" character and the /// following character in the decoded data without any transformation and, if /// possible, indicate to the user that proper decoding was not possible at /// this point in the data. /// ///
/// /// The string to decode which cannot have length above or equal to 3 /// and must start with an equal sign. /// /// A decoded byte array /// If is /// /// Thrown if a the parameter has length above 2 or does not /// start with an equal sign. /// private static byte[] DecodeEqualSignNotLongEnough(string decode) { if (decode == null) throw new ArgumentNullException(nameof(decode)); // We can only decode wrong length equal signs if (decode.Length >= 3) throw new ArgumentException(@"decode must have length lower than 3", nameof(decode)); if (decode.Length <= 0) throw new ArgumentException(@"decode must have length lower at least 1", nameof(decode)); // First char must be = if (decode[0] != '=') throw new ArgumentException(@"First part of decode must be an equal sign", nameof(decode)); // We will now believe that the string sent to us, was actually not encoded // Therefore it must be in US-ASCII and we will return the bytes it corrosponds to return Encoding.ASCII.GetBytes(decode); } #endregion #region DecodeEqualSign /// /// This helper method will decode a string of the form "=XX" where X is any character.
/// This method will never fail, unless an argument of length not equal to three is passed. ///
/// The length 3 character that needs to be decoded /// A decoded byte array /// If is /// /// Thrown if a the parameter does not have length 3 or does /// not start with an equal sign. /// private static byte[] DecodeEqualSign(string decode) { if (decode == null) throw new ArgumentNullException(nameof(decode)); // We can only decode the string if it has length 3 - other calls to this function is invalid if (decode.Length != 3) throw new ArgumentException(@"decode must have length 3", nameof(decode)); // First char must be = if (decode[0] != '=') throw new ArgumentException(@"decode must start with an equal sign", nameof(decode)); // There are two cases where an equal sign might appear // It might be a // - hex-string like =3D, denoting the character with hex value 3D // - it might be the last character on the line before a CRLF // pair, denoting a soft linebreak, which simply // splits the text up, because of the 76 chars per line restriction if (decode.Contains("\r\n")) return new byte[0]; // Hex string detected. Convertion needed. // It might be that the string located after the equal sign is not hex characters // An example: =JU // In that case we would like to catch the FormatException and do something else try { // The number part of the string is the last two digits. Here we simply remove the equal sign var numberString = decode.Substring(1); // Now we create a byte array with the converted number encoded in the string as a hex value (base 16) // This will also handle illegal encodings like =3d where the hex digits are not uppercase, // which is a robustness requirement from RFC 2045. var oneByte = new[] { Convert.ToByte(numberString, 16) }; // Simply return our one byte byte array return oneByte; } catch (FormatException) { // RFC 2045 says about robust implementation: // An "=" followed by a character that is neither a // hexadecimal digit (including "abcdef") nor the CR // character of a CRLF pair is illegal. This case can be // the result of US-ASCII text having been included in a // quoted-printable part of a message without itself // having been subjected to quoted-printable encoding. A // reasonable approach by a robust implementation might be // to include the "=" character and the following // character in the decoded data without any // transformation and, if possible, indicate to the user // that proper decoding was not possible at this point in // the data. // So we choose to believe this is actually an un-encoded string // Therefore it must be in US-ASCII and we will return the bytes it corrosponds to return Encoding.ASCII.GetBytes(decode); } } #endregion } ================================================ FILE: MsgKit/Mime/Decode/Rfc2231Decoder.cs ================================================ using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; namespace MsgKit.Mime.Decode; /// /// This class is responsible for decoding parameters that has been encoded with:
/// /// /// Continuation
/// This is where a single parameter has such a long value that it could /// be wrapped while in transit. Instead multiple parameters is used on each line.
///
/// Example
/// From: Content-Type: text/html; boundary="someVeryLongStringHereWhichCouldBeWrappedInTransit"
/// To: /// Content-Type: text/html; boundary*0="someVeryLongStringHere" boundary*1="WhichCouldBeWrappedInTransit" ///
///
/// /// Encoding
/// Sometimes other characters then ASCII characters are needed in parameters.
/// The parameter is then given a different name to specify that it is encoded.
///
/// Example
/// From: Content-Disposition attachment; filename="specialCharsÆØÅ"
/// To: Content-Disposition attachment; filename*="ISO-8859-1'en-us'specialCharsC6D8C0"
/// This encoding is almost the same as encoding, and is used to decode the value. ///
///
/// /// Continuation and Encoding
/// Both Continuation and Encoding can be used on the same time.
///
/// Example
/// From: Content-Disposition attachment; filename="specialCharsÆØÅWhichIsSoLong"
/// To: /// /// Content-Disposition attachment; filename*0*="ISO-8859-1'en-us'specialCharsC6D8C0"; /// filename*1*="WhichIsSoLong" /// ///
/// This could also be encoded as:
/// To: /// /// Content-Disposition attachment; filename*0*="ISO-8859-1'en-us'specialCharsC6D8C0"; /// filename*1="WhichIsSoLong" /// ///
/// Notice that filename*1 does not have an * after it - denoting it IS NOT encoded.
/// There are some rules about this:
/// /// The encoding must be mentioned in the first part (filename*0*), which has to be encoded. /// /// No other part must specify an encoding, but if encoded it uses the encoding mentioned in the /// first part. /// /// Parts may be encoded or not in any order. /// ///
///
///
/// More information and the specification is available in /// RFC 2231. ///
internal static class Rfc2231Decoder { #region Decode /// /// Decodes a string of the form:
/// value0; key1=value1; key2=value2; key3=value3
/// The returned List of key value pairs will have the key as key and the decoded value as value.
/// The first value0 will have a key of .
///
/// If continuation is used, then multiple keys will be merged into one key with the different values /// decoded into on big value for that key.
/// Example:
/// /// title*0=part1 /// title*1=part2 /// /// will have key and value of:

/// title=decode(part1)decode(part2) ///
/// The string to decode. /// A list of decoded key value pairs. /// If is public static List> Decode(string toDecode) { if (toDecode == null) throw new ArgumentNullException(nameof(toDecode)); // Normalize the input to take account for missing semicolons after parameters. // Example // text/plain; charset=\"iso-8859-1\" name=\"somefile.txt\" or // text/plain;\tcharset=\"iso-8859-1\"\tname=\"somefile.txt\" // is normalized to // text/plain; charset=\"iso-8859-1\"; name=\"somefile.txt\" // Only works for parameters inside quotes // \s = matches whitespace toDecode = Regex.Replace(toDecode, "=\\s*\"(?[^\"]*)\"\\s", "=\"${value}\"; "); // Normalize // Since the above only works for parameters inside quotes, we need to normalize // the special case with the first parameter. // Example: // attachment filename="foo" // is normalized to // attachment; filename="foo" // ^ = matches start of line (when not inside square bracets []) toDecode = Regex.Replace(toDecode, @"^(?[^;\s]+)\s(?[^;\s]+)", "${first}; ${second}"); // Split by semicolon, but only if not inside quotes var splitted = Utility.SplitStringWithCharNotInsideQuotes(toDecode.Trim(), ';'); var collection = new List>(splitted.Count); foreach (var part in splitted) { // Empty strings should not be processed if (part.Trim().Length == 0) continue; var keyValue = part.Trim().Split(new[] { '=' }, 2); switch (keyValue.Length) { case 1: collection.Add(new KeyValuePair("", keyValue[0])); break; case 2: collection.Add(new KeyValuePair(keyValue[0], keyValue[1])); break; default: throw new ArgumentException("When splitting the part \"" + part + "\" by = there was " + keyValue.Length + " parts. Only 1 and 2 are supported"); } } return DecodePairs(collection); } #endregion #region DecodePairs /// /// Decodes the list of key value pairs into a decoded list of key value pairs.
/// There may be less keys in the decoded list, but then the values for the lost keys will have been appended /// to the new key. ///
/// The pairs to decode /// A decoded list of pairs private static List> DecodePairs(IList> pairs) { if (pairs == null) throw new ArgumentNullException(nameof(pairs)); var resultPairs = new List>(pairs.Count); var pairsCount = pairs.Count; for (var i = 0; i < pairsCount; i++) { var currentPair = pairs[i]; var key = currentPair.Key; var value = Utility.RemoveQuotesIfAny(currentPair.Value); // Is it a continuation parameter? (encoded or not) if (key.EndsWith("*0", StringComparison.OrdinalIgnoreCase) || key.EndsWith("*0*", StringComparison.OrdinalIgnoreCase)) { // This encoding will not be used if we get into the if which tells us // that the whole continuation is not encoded var encoding = "notEncoded - Value here is never used"; // Now lets find out if it is encoded too. if (key.EndsWith("*0*", StringComparison.OrdinalIgnoreCase)) { // It is encoded. // Fetch out the encoding for later use and decode the value // If the value was not encoded as the email specified // encoding will be set to null. This will be used later. value = DecodeSingleValue(value, out encoding); // Find the right key to use to store the full value // Remove the start *0 which tells is it is a continuation, and the first one // And remove the * afterwards which tells us it is encoded key = key.Replace("*0*", ""); } else { // It is not encoded, and no parts of the continuation is encoded either // Find the right key to use to store the full value // Remove the start *0 which tells is it is a continuation, and the first one key = key.Replace("*0", ""); } // The StringBuilder will hold the full decoded value from all continuation parts var builder = new StringBuilder(); // Append the decoded value builder.Append(value); // Now go trough the next keys to see if they are part of the continuation for (int j = i + 1, continuationCount = 1; j < pairsCount; j++, continuationCount++) { var jKey = pairs[j].Key; var valueJKey = Utility.RemoveQuotesIfAny(pairs[j].Value); if (jKey.Equals(key + "*" + continuationCount)) { // This value part of the continuation is not encoded // Therefore remove qoutes if any and add to our stringbuilder builder.Append(valueJKey); // Remember to increment i, as we have now treated one more KeyValuePair i++; } else if (jKey.Equals(key + "*" + continuationCount + "*")) { // We will not get into this part if the first part was not encoded // Therefore the encoding will only be used if and only if the // first part was encoded, in which case we have remembered the encoding used // Sometimes an email creator says that a string was encoded, but it really // `was not. This is to catch that problem. if (encoding != null) valueJKey = DecodeSingleValue(valueJKey, encoding); builder.Append(valueJKey); // Remember to increment i, as we have now treated one more KeyValuePair i++; } else { // No more keys for this continuation break; } } // Add the key and the full value as a pair value = builder.ToString(); resultPairs.Add(new KeyValuePair(key, value)); } else if (key.EndsWith("*", StringComparison.OrdinalIgnoreCase)) { // This parameter is only encoded - it is not part of a continuation // We need to change the key from "*" to "" and decode the value // To get the key we want, we remove the last * that denotes // that the value hold by the key was encoded key = key.Replace("*", ""); // Decode the value string throwAway; value = DecodeSingleValue(value, out throwAway); // Now input the new value with the new key resultPairs.Add(new KeyValuePair(key, value)); } else { // Fully normal key - the value is not encoded // Therefore nothing to do, and we can simply pass the pair // as being decoded now resultPairs.Add(currentPair); } } return resultPairs; } #endregion #region DecodeSingleValue /// /// This will decode a single value of the form: ISO-8859-1'en-us'%3D%3DIamHere
/// Which is basically a form just using % instead of =
/// Notice that 'en-us' part is not used for anything.
///
/// If the single value given is not on the correct form, it will be returned without /// being decoded and will be set to . ///
/// /// The encoding used to decode with - it is given back for later use.
/// if input was not in the correct form. /// /// The value to decode /// /// The decoded value that corresponds to or if /// is not on the correct form, it will be non-decoded. /// /// If is private static string DecodeSingleValue(string toDecode, out string encodingUsed) { if (toDecode == null) throw new ArgumentNullException(nameof(toDecode)); // Check if input has a part describing the encoding if (toDecode.IndexOf('\'') == -1) { // The input was not encoded (at least not valid) and it is returned as is encodingUsed = null; return toDecode; } encodingUsed = toDecode.Substring(0, toDecode.IndexOf('\'')); toDecode = toDecode.Substring(toDecode.LastIndexOf('\'') + 1); return DecodeSingleValue(toDecode, encodingUsed); } #endregion #region DecodeSingleValue /// /// This will decode a single value of the form: %3D%3DIamHere /// Which is basically a form just using % instead of = /// /// The value to decode /// The encoding used to decode with /// The decoded value that corresponds to /// If is /// If is private static string DecodeSingleValue(string valueToDecode, string encoding) { if (valueToDecode == null) throw new ArgumentNullException(nameof(valueToDecode)); if (encoding == null) throw new ArgumentNullException(nameof(encoding)); // The encoding used is the same as QuotedPrintable, we only // need to change % to = // And otherwise make it look like the correct EncodedWord encoding valueToDecode = "=?" + encoding + "?Q?" + valueToDecode.Replace("%", "=") + "?="; return EncodedWord.Decode(valueToDecode); } #endregion } ================================================ FILE: MsgKit/Mime/Decode/Rfc2822DateTime.cs ================================================ using System; using System.Globalization; using System.Text.RegularExpressions; namespace MsgKit.Mime.Decode; /// /// Class used to decode RFC 2822 Date header fields. /// internal static class Rfc2822DateTime { #region Fields /// /// Custom DateTime formats - will be tried if cannot parse the dateInput string using the default method /// Specified using formats at http://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx /// One format per string in the array /// public static string[] CustomDateTimeFormats { private get; set; } #endregion #region StringToDate /// /// Converts a string in RFC 2822 format into a object /// /// The date to convert /// /// A valid object, which represents the same time as the string that was converted. /// If is not a valid date representation, then is /// returned. /// /// If is /// /// If the could not be parsed into a /// object /// public static DateTime StringToDate(string inputDate) { if (inputDate == null) throw new ArgumentNullException(nameof(inputDate)); // Handle very wrong date time format: Tue Feb 18 10:23:30 2014 (MSK) inputDate = FixSpecialCases(inputDate); // Old date specification allows comments and a lot of whitespace inputDate = StripCommentsAndExcessWhitespace(inputDate); try { // Extract the DateTime var dateTime = ExtractDateTime(inputDate); // Bail if we could not parse the date if (dateTime == DateTime.MinValue) return dateTime; // Convert the date into UTC dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc); // Adjust according to the time zone dateTime = AdjustTimezone(dateTime, inputDate); // Return the parsed date return dateTime; } catch (FormatException e) // Convert.ToDateTime() Failure { throw new ArgumentException( "Could not parse date: " + e.Message + ". Input was: \"" + inputDate + "\"", e); } catch (ArgumentException e) { throw new ArgumentException( "Could not parse date: " + e.Message + ". Input was: \"" + inputDate + "\"", e); } } #endregion #region AdjustTimezone /// /// Adjust the object given according to the timezone specified in the /// . /// /// The date to alter /// The input date, in which the timezone can be found /// An date altered according to the timezone private static DateTime AdjustTimezone(DateTime dateTime, string dateInput) { // We know that the timezones are always in the last part of the date input var parts = dateInput.Split(' '); var lastPart = parts[parts.Length - 1]; // Convert timezones in older formats to [+-]dddd format. lastPart = Regex.Replace(lastPart, RegexOldTimezoneFormats, MatchEvaluator); // Find the timezone specification // Example: Fri, 21 Nov 1997 09:55:06 -0600 // finds -0600 var match = Regex.Match(lastPart, RegexNewTimezoneFormats); if (!match.Success) return dateTime; // We have found that the timezone is in +dddd or -dddd format // Add the number of hours and minutes to our found date var hours = int.Parse(match.Groups["hours"].Value); var minutes = int.Parse(match.Groups["minutes"].Value); var factor = match.Value[0] == '+' ? -1 : 1; dateTime = dateTime.AddHours(factor * hours); dateTime = dateTime.AddMinutes(factor * minutes); return dateTime; // A timezone of -0000 is the same as doing nothing } #endregion #region MatchEvaluator /// /// Convert timezones in older formats to [+-]dddd format. /// /// The match that was found /// The string to replace the matched string with /// /// RFC 2822: http://www.rfc-base.org/rfc-2822.html /// 4.3. Obsolete Date and Time /// The syntax for the obsolete date format allows a 2 digit year in the /// date field and allows for a list of alphabetic time zone /// specifications that were used in earlier versions of this standard. /// It also permits comments and folding white space between many of the /// tokens. /// obs-day-of-week = [CFWS] day-name [CFWS] /// obs-year = [CFWS] 2*DIGIT [CFWS] /// obs-month = CFWS month-name CFWS /// obs-day = [CFWS] 1*2DIGIT [CFWS] /// obs-hour = [CFWS] 2DIGIT [CFWS] /// obs-minute = [CFWS] 2DIGIT [CFWS] /// obs-second = [CFWS] 2DIGIT [CFWS] /// obs-zone = "UT" / "GMT" / ; Universal Time /// Resnick Standards Track [Page 31] /// RFC 2822 Internet Message Format April 2001 /// ; North American UT /// ; offsets /// "EST" / "EDT" / ; Eastern: - 5/ - 4 /// "CST" / "CDT" / ; Central: - 6/ - 5 /// "MST" / "MDT" / ; Mountain: - 7/ - 6 /// "PST" / "PDT" / ; Pacific: - 8/ - 7 /// %d65-73 / ; Military zones - "A" /// %d75-90 / ; through "I" and "K" /// %d97-105 / ; through "Z", both /// %d107-122 ; upper and lower case -- imported lower and upper /// private static string MatchEvaluator(Match match) { if (!match.Success) throw new ArgumentException("Match success are always true"); switch (match.Value) { // "A" through "I" and "a" through "i" // are equivalent to "+0100" through "+0900" respectively case "A": case "a": return "+0100"; case "B": case "b": return "+0200"; case "C": case "c": return "+0300"; case "D": case "d": return "+0400"; case "E": case "e": return "+0500"; case "F": case "f": return "+0600"; case "G": case "g": return "+0700"; case "H": case "h": return "+0800"; case "I": case "i": return "+0900"; // "K", "L", and "M" and "k", "l" and "m" // are equivalent to "+1000", "+1100", and "+1200" respectively case "K": case "k": return "+1000"; case "L": case "l": return "+1100"; case "M": case "m": return "+1200"; // "N" through "Y" and "n" through "y" // are equivalent to "-0100" through "-1200" respectively case "N": case "n": return "-0100"; case "O": case "o": return "-0200"; case "P": case "p": return "-0300"; case "Q": case "q": return "-0400"; case "R": case "r": return "-0500"; case "S": case "s": return "-0600"; case "T": case "t": return "-0700"; case "U": case "u": return "-0800"; case "V": case "v": return "-0900"; case "W": case "w": return "-1000"; case "X": case "x": return "-1100"; case "Y": case "y": return "-1200"; // "Z", "z", "UT" and "GMT" // is equivalent to "+0000" case "Z": case "z": case "UT": case "GMT": return "+0000"; // US time zones case "EDT": return "-0400"; // EDT is semantically equivalent to -0400 case "EST": return "-0500"; // EST is semantically equivalent to -0500 case "CDT": return "-0500"; // CDT is semantically equivalent to -0500 case "CST": return "-0600"; // CST is semantically equivalent to -0600 case "MDT": return "-0600"; // MDT is semantically equivalent to -0600 case "MST": return "-0700"; // MST is semantically equivalent to -0700 case "PDT": return "-0700"; // PDT is semantically equivalent to -0700 case "PST": return "-0800"; // PST is semantically equivalent to -0800 // EU time zones case "MSK": return "+0400"; // MSK is semantically equivalent to +0400 default: throw new ArgumentException("Unexpected input"); } } #endregion #region ExtractDateTime /// /// Extracts the date and time parts from the /// /// The date input string, from which to extract the date and time parts /// /// The extracted date part or if is not /// recognized as a valid date. /// /// If is private static DateTime ExtractDateTime(string dateInput) { if (dateInput == null) throw new ArgumentNullException(nameof(dateInput)); // Matches the date and time part of a string // Given string example: Fri, 21 Nov 1997 09:55:06 -0600 // Needs to find: 21 Nov 1997 09:55:06 // Seconds does not need to be specified // Even though it is illigal, sometimes hours, minutes or seconds are only specified with one digit // Year with 2 or 4 digits (1922 or 22) const string year = @"(\d\d\d\d|\d\d)"; // Time with one or two digits for hour and minute and optinal seconds (06:04:06 or 6:4:6 or 06:04 or 6:4) const string time = @"\d?\d:\d?\d(:\d?\d)?"; // Correct format is 21 Nov 1997 09:55:06 const string correctFormat = @"\d\d? .+ " + year + " " + time; // Some uses incorrect format: 2012-1-1 12:30 const string incorrectFormat = year + @"-\d?\d-\d?\d " + time; // Some uses incorrect format: 08-May-2012 16:52:30 +0100 const string correctFormatButWithDashes = @"\d\d?-[A-Za-z]{3}-" + year + " " + time; // We allow both correct and incorrect format const string joinedFormat = @"(" + correctFormat + ")|(" + incorrectFormat + ")|(" + correctFormatButWithDashes + ")"; var match = Regex.Match(dateInput, joinedFormat); if (match.Success) try { return Convert.ToDateTime(match.Value, CultureInfo.InvariantCulture); } catch (FormatException) { } //If there are some custom formats if (CustomDateTimeFormats == null) return DateTime.MinValue; //If there is a timezone at the end, remove it var strDate = dateInput.Trim(); if (strDate.Contains(" ") ) //Check contains a space before getting the last part to prevent accessing index -1 { var parts = strDate.Split(' '); var lastPart = parts[parts.Length - 1]; // Convert timezones in older formats to [+-]dddd format. lastPart = Regex.Replace(lastPart, RegexOldTimezoneFormats, MatchEvaluator); // Find the timezone specification // Example: Fri, 21 Nov 1997 09:55:06 -0600 // finds -0600 var timezoneMatch = Regex.Match(lastPart, RegexNewTimezoneFormats); if (timezoneMatch.Success) strDate = strDate.Substring(0, strDate.Length - parts[parts.Length - 1].Length) .Trim(); //Use the length of the old last part } //Try and parse it as one of the custom formats try { return DateTime.ParseExact(strDate, CustomDateTimeFormats, null, DateTimeStyles.None); } catch (FormatException) { } return DateTime.MinValue; } #endregion #region StripCommentsAndExcessWhitespace /// /// Strips and removes all comments and excessive whitespace from the string /// /// The input to strip from /// The stripped string /// If is private static string StripCommentsAndExcessWhitespace(string input) { if (input == null) throw new ArgumentNullException(nameof(input)); // Strip out comments // Also strips out nested comments input = Regex.Replace(input, @"(\((?>\((?)|\)(?<-C>)|.?)*(?(C)(?!))\))", ""); // Reduce any whitespace character to one space only input = Regex.Replace(input, @"\s+", " "); // Remove all initial whitespace input = Regex.Replace(input, @"^\s+", ""); // Remove all ending whitespace input = Regex.Replace(input, @"\s+$", ""); // Remove spaces at colons // Example: 22: 33 : 44 => 22:33:44 input = Regex.Replace(input, @" ?: ?", ":"); return input; } #endregion #region FixSpecialCases /// /// Converts date time string in very wrong date time format: /// Tue Feb 18 10:23:30 2014 (MSK) /// to /// Feb 18 2014 10:23:30 MSK /// /// The date to convert /// The corrected string private static string FixSpecialCases(string inputDate) { const string weekDayPattern = "(?Mon|Tue|Wed|Thu|Fri|Sat|Sun)"; const string monthPattern = @"(?[A-Za-z]+)"; const string dayPattern = @"(?\d?\d)"; const string yearPattern = @"(?\d\d\d\d)"; const string timePattern = @"(?