/// <summary> /// Writes all <see cref="Property">properties</see> either as a <see cref="CFStream"/> or as a collection in /// a <see cref="PropertyTags.PropertiesStreamName"/> stream to the given <paramref name="storage"/>, this depends /// on the <see cref="PropertyType"/> /// </summary> /// <remarks> /// See the <see cref="Properties"/> class it's <see cref="Properties.WriteProperties"/> method for the logic /// that is used to determine this /// </remarks> /// <param name="storage">The <see cref="CFStorage"/></param> /// <returns> /// Total size of the written <see cref="Recipient"/> object and it's <see cref="Properties"/> /// </returns> internal long WriteProperties(CFStorage storage) { var propertiesStream = new RecipientProperties(); propertiesStream.AddProperty(PropertyTags.PR_ROWID, RowId); propertiesStream.AddProperty(PropertyTags.PR_ENTRYID, Mapi.GenerateEntryId()); propertiesStream.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey()); propertiesStream.AddProperty(PropertyTags.PR_RECIPIENT_TYPE, RecipientType); propertiesStream.AddProperty(PropertyTags.PR_ADDRTYPE_W, AddressTypeString); propertiesStream.AddProperty(PropertyTags.PR_EMAIL_ADDRESS_W, Email); propertiesStream.AddProperty(PropertyTags.PR_OBJECT_TYPE, ObjectType); propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_TYPE, DisplayType); propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_NAME_W, DisplayName); propertiesStream.AddProperty(PropertyTags.PR_SEARCH_KEY, Mapi.GenerateSearchKey(AddressTypeString, Email)); return(propertiesStream.WriteProperties(storage)); }
/// <summary> /// Writes all the properties that are part of the <see cref="Email"/> object either as <see cref="CFStorage"/>'s /// or <see cref="CFStream"/>'s to the <see cref="CompoundFile.RootStorage"/> /// </summary> internal void WriteToStorage() { var rootStorage = CompoundFile.RootStorage; 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; if (!string.IsNullOrEmpty(InternetMessageId)) { TopLevelProperties.AddProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, InternetMessageId); } 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); TopLevelProperties.AddProperty(PropertyTags.PR_TRANSPORT_MESSAGE_HEADERS_W, TransportMessageHeaders); 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)) { TopLevelProperties.AddProperty(PropertyTags.PR_HTML, BodyHtml); } if (Draft) { messageFlags |= MessageFlags.MSGFLAG_UNSENT | MessageFlags.MSGFLAG_FROMME; IconIndex = MessageIconIndex.UnsentMail; if (string.IsNullOrWhiteSpace(BodyRtf) && !string.IsNullOrWhiteSpace(BodyHtml)) { BodyRtf = Strings.GetEscapedRtf(BodyHtml); BodyRtfCompressed = true; } } if (!SentOn.HasValue) { SentOn = DateTime.UtcNow; } TopLevelProperties.AddProperty(PropertyTags.PR_CLIENT_SUBMIT_TIME, SentOn.Value.ToUniversalTime()); TopLevelProperties.AddProperty(PropertyTags.PR_MESSAGE_FLAGS, messageFlags); 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); TopLevelProperties.AddProperty(PropertyTags.PR_ICON_INDEX, IconIndex); if (Sender != null) { Sender.WriteProperties(TopLevelProperties); } if (Receiving != null) { Receiving.WriteProperties(TopLevelProperties); } if (Representing != null) { Representing.WriteProperties(TopLevelProperties); } if (ReceivingRepresenting != null) { ReceivingRepresenting.WriteProperties(TopLevelProperties); } if (recipientCount > 0) { var displayTo = new List <string>(); var displayCc = new List <string>(); var displayBcc = new List <string>(); 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(); } } 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); } if (!string.IsNullOrEmpty(BodyRtf) && BodyRtfCompressed) { TopLevelProperties.AddProperty(PropertyTags.PR_RTF_COMPRESSED, RtfCompressor.Compress(Encoding.ASCII.GetBytes(BodyRtf))); TopLevelProperties.AddProperty(PropertyTags.PR_RTF_IN_SYNC, true); } }
/// <summary> /// Writes all the properties that are part of the <see cref="Appointment"/> object either as <see cref="CFStorage"/>'s /// or <see cref="CFStream"/>'s to the <see cref="CompoundFile.RootStorage"/> /// </summary> private void WriteToStorage() { var rootStorage = CompoundFile.RootStorage; long messageSize = 0; messageSize += Recipients.WriteToStorage(rootStorage); messageSize += Attachments.WriteToStorage(rootStorage); var recipientCount = Recipients.Count; var attachmentCount = Attachments.Count; var propertiesStream = new TopLevelProperties(recipientCount, attachmentCount, recipientCount, attachmentCount); if (!string.IsNullOrEmpty(InternetMessageId)) { propertiesStream.AddProperty(PropertyTags.PR_INTERNET_MESSAGE_ID_W, InternetMessageId); } propertiesStream.AddProperty(PropertyTags.PR_ENTRYID, Mapi.GenerateEntryId()); propertiesStream.AddProperty(PropertyTags.PR_INSTANCE_KEY, Mapi.GenerateInstanceKey()); propertiesStream.AddProperty(PropertyTags.PR_STORE_SUPPORT_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_STORE_UNICODE_MASK, StoreSupportMaskConst.StoreSupportMask, PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_ALTERNATE_RECIPIENT_ALLOWED, true, PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_HASATTACH, attachmentCount > 0); var messageFlags = MessageFlags.MSGFLAG_UNMODIFIED; if (Draft) { messageFlags |= MessageFlags.MSGFLAG_UNSENT | MessageFlags.MSGFLAG_FROMME; IconIndex = MessageIconIndex.UnsentMail; } if (attachmentCount > 0) { messageFlags |= MessageFlags.MSGFLAG_HASATTACH; } if (!SentOn.HasValue) { SentOn = DateTime.UtcNow; } propertiesStream.AddProperty(PropertyTags.PR_CLIENT_SUBMIT_TIME, SentOn); propertiesStream.AddProperty(PropertyTags.PR_MESSAGE_FLAGS, messageFlags); propertiesStream.AddProperty(PropertyTags.PR_ACCESS, MapiAccess.MAPI_ACCESS_DELETE | MapiAccess.MAPI_ACCESS_MODIFY | MapiAccess.MAPI_ACCESS_READ); propertiesStream.AddProperty(PropertyTags.PR_ACCESS_LEVEL, MapiAccess.MAPI_ACCESS_MODIFY); propertiesStream.AddProperty(PropertyTags.PR_OBJECT_TYPE, MapiObjectType.MAPI_MESSAGE); SetSubject(); propertiesStream.AddProperty(PropertyTags.PR_SUBJECT_W, Subject); propertiesStream.AddProperty(PropertyTags.PR_NORMALIZED_SUBJECT_W, SubjectNormalized); propertiesStream.AddProperty(PropertyTags.PR_SUBJECT_PREFIX_W, SubjectPrefix); propertiesStream.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; propertiesStream.AddProperty(PropertyTags.PR_CREATION_TIME, utcNow); propertiesStream.AddProperty(PropertyTags.PR_LAST_MODIFICATION_TIME, utcNow); propertiesStream.AddProperty(PropertyTags.PR_MESSAGE_CLASS_W, "IPM.Appointment"); propertiesStream.AddProperty(PropertyTags.PR_PRIORITY, Priority); propertiesStream.AddProperty(PropertyTags.PR_IMPORTANCE, Importance); propertiesStream.AddProperty(PropertyTags.PR_MESSAGE_LOCALE_ID, CultureInfo.CurrentCulture.LCID); propertiesStream.AddProperty(PropertyTags.PR_ICON_INDEX, IconIndex); if (Sender != null) { Sender.WriteProperties(propertiesStream); } if (Receiving != null) { Receiving.WriteProperties(propertiesStream); } if (Representing != null) { Representing.WriteProperties(propertiesStream); } if (ReceivingRepresenting != null) { ReceivingRepresenting.WriteProperties(propertiesStream); } if (recipientCount > 0) { var displayTo = new List <string>(); var displayCc = new List <string>(); var displayBcc = new List <string>(); 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(); } } propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_TO_W, string.Join(";", displayTo), PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_CC_W, string.Join(";", displayCc), PropertyFlags.PROPATTR_READABLE); propertiesStream.AddProperty(PropertyTags.PR_DISPLAY_BCC_W, string.Join(";", displayBcc), PropertyFlags.PROPATTR_READABLE); } propertiesStream.AddProperty(PropertyTags.PR_INTERNET_CPID, Encoding.UTF8.CodePage); if (BodyRtfCompressed) { propertiesStream.AddProperty(PropertyTags.PR_RTF_COMPRESSED, RTFCompressor.Compress(Encoding.ASCII.GetBytes(BodyRtf))); propertiesStream.AddProperty(PropertyTags.PR_RTF_IN_SYNC, true); } var namedProperties = new NamedProperties(propertiesStream); //Uses the top level properties. 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); namedProperties.WriteProperties(rootStorage); propertiesStream.WriteProperties(rootStorage, messageSize); }