/// <summary> /// Parses set of <see cref="StringSegment"/> supplying the individual lines of a <c>multipart</c> body, returning contituent parts. /// </summary> /// <param name="bodyLines">The <c>multipart</c> body lines</param> /// <param name="boundary">The <c>multipart</c> boundary string</param> /// <returns>The constituent body parts.</returns> public static IEnumerable <MimePart> ReadBodyParts(IEnumerable <StringSegment> bodyLines, string boundary) { if (bodyLines == null) { throw new ArgumentNullException("bodyLines"); } if (string.IsNullOrEmpty(boundary)) { throw new MimeException(MimeError.MissingBoundarySeparator); } IEnumerator <StringSegment> lineEnumerator = bodyLines.GetEnumerator(); StringSegment part = StringSegment.Null; StringSegment prevLine = StringSegment.Null; MimePartType expectedPart = MimePartType.BodyPrologue; // // As per the Multipart Spec: // The boundary delimiter is actually CRLF--boundary // So we must maintain a stack (prevLine).. // while (expectedPart != MimePartType.BodyEpilogue && lineEnumerator.MoveNext()) { StringSegment line = lineEnumerator.Current; if (IsBoundary(line, boundary)) { if (!part.IsNull) { part.Union(prevLine); } // // When we hit a boundary, we yield the part we've collected so far // MimePartType partType = expectedPart; switch (expectedPart) { default: throw new MimeException(MimeError.InvalidBodySubpart); case MimePartType.BodyPrologue: expectedPart = MimePartType.BodyPart; break; case MimePartType.BodyPart: if (IsBoundaryEnd(line)) { expectedPart = MimePartType.BodyEpilogue; } break; } if (!part.IsNull) { yield return(new MimePart(partType, part)); } prevLine = StringSegment.Null; part = StringSegment.Null; } else { if (!prevLine.IsNull) { part.Union(prevLine); } prevLine = line; } } if (expectedPart != MimePartType.BodyEpilogue) { throw new MimeException(MimeError.InvalidBodySubpart); } // Epilogue part = StringSegment.Null; while (lineEnumerator.MoveNext()) { part.Union(lineEnumerator.Current); } if (!part.IsEmpty) { yield return(new MimePart(MimePartType.BodyEpilogue, part)); } }
/// <summary> /// Expands the source segment for this entity /// </summary> internal virtual void AppendSourceText(StringSegment segment) { m_sourceText.Union(segment); }