/// <summary> /// Extract the header part and body part of a message.<br/> /// The headers are then parsed to a strongly typed <see cref="MessageHeader"/> object. /// </summary> /// <param name="fullRawMessage">The full message in bytes where header and body needs to be extracted from</param> /// <param name="headers">The extracted header parts of the message</param> /// <param name="body">The body part of the message</param> /// <exception cref="ArgumentNullException">If <paramref name="fullRawMessage"/> is <see langword="null"/></exception> public static void ExtractHeadersAndBody(byte[] fullRawMessage, out MessageHeader headers, out byte[] body) { if (fullRawMessage == null) throw new ArgumentNullException("fullRawMessage"); // Find the end location of the headers var endOfHeaderLocation = FindHeaderEndPosition(fullRawMessage); // The headers are always in ASCII - therefore we can convert the header part into a string // using US-ASCII encoding //var headersString = Encoding.ASCII.GetString(fullRawMessage, 0, endOfHeaderLocation); // MIME headers should aways be ASCII encoded, but sometimes they don't so we read then as UTF8. // It should not make any difference if we do it this way because UTF-8 superseeds ASCII encoding var headersString = Encoding.UTF8.GetString(fullRawMessage, 0, endOfHeaderLocation); // Now parse the headers to a NameValueCollection var headersUnparsedCollection = ExtractHeaders(headersString); // Use the NameValueCollection to parse it into a strongly-typed MessageHeader header headers = new MessageHeader(headersUnparsedCollection); // Since we know where the headers end, we also know where the body is // Copy the body part into the body parameter body = new byte[fullRawMessage.Length - endOfHeaderLocation]; Array.Copy(fullRawMessage, endOfHeaderLocation, body, 0, body.Length); }
/// <summary> /// Figures out the filename of this message part. /// <see cref="FileName"/> property. /// </summary> /// <param name="rawBody">The body that needs to be parsed</param> /// <param name="headers">The headers that should be used from the message</param> /// <param name="defaultName">The default filename to use, if no other could be found</param> /// <returns>The filename found, or the default one if not such filename could be found in the headers</returns> /// <exception cref="ArgumentNullException">if <paramref name="headers"/> is <see langword="null"/></exception> private static string FindFileName(byte[] rawBody, MessageHeader headers, string defaultName) { if (headers == null) throw new ArgumentNullException("headers"); if (headers.ContentDisposition != null && headers.ContentDisposition.FileName != null) return FileManager.RemoveInvalidFileNameChars(headers.ContentDisposition.FileName); var extensionFromContentType = string.Empty; string contentTypeName = null; if (headers.ContentType != null) { extensionFromContentType = MimeType.GetExtensionFromMimeType(headers.ContentType.MediaType); contentTypeName = headers.ContentType.Name; } if (!string.IsNullOrEmpty(headers.ContentDescription)) return FileManager.RemoveInvalidFileNameChars(headers.ContentDescription + extensionFromContentType); if (!string.IsNullOrEmpty(headers.Subject)) return FileManager.RemoveInvalidFileNameChars(headers.Subject) + extensionFromContentType; if (extensionFromContentType.Equals(".eml", StringComparison.OrdinalIgnoreCase)) { try { var message = new Message(rawBody); if (message.Headers != null && !string.IsNullOrEmpty(message.Headers.Subject)) return FileManager.RemoveInvalidFileNameChars(message.Headers.Subject) + extensionFromContentType; } // ReSharper disable once EmptyGeneralCatchClause catch { } } return !string.IsNullOrEmpty(contentTypeName) ? FileManager.RemoveInvalidFileNameChars(contentTypeName) : FileManager.RemoveInvalidFileNameChars(defaultName + extensionFromContentType); }
/// <summary> /// Used to construct the topmost message part /// </summary> /// <param name="rawBody">The body that needs to be parsed</param> /// <param name="headers">The headers that should be used from the message</param> /// <exception cref="ArgumentNullException">If <paramref name="rawBody"/> or <paramref name="headers"/> /// is <see langword="null"/></exception> internal MessagePart(byte[] rawBody, MessageHeader headers) { if(rawBody == null) throw new ArgumentNullException("rawBody"); if(headers == null) throw new ArgumentNullException("headers"); ContentType = headers.ContentType; ContentDescription = headers.ContentDescription; ContentTransferEncoding = headers.ContentTransferEncoding; ContentId = headers.ContentId; ContentDisposition = headers.ContentDisposition; FileName = FindFileName(rawBody, headers, LanguageConsts.NameLessFileName); BodyEncoding = ParseBodyEncoding(ContentType.CharSet); ParseBody(rawBody); }