Ejemplo n.º 1
0
        public void TestSimplePlainTextBody()
        {
            const string expected = "(\"text\" \"plain\" (\"charset\" \"us-ascii\" \"name\" \"body.txt\") NIL NIL \"7bit\" 3028 NIL NIL NIL NIL 92)";
            BodyPartText text, parsed;
            BodyPart     body;

            text = new BodyPartText {
                ContentType = new ContentType("text", "plain")
                {
                    Charset = "us-ascii", Name = "body.txt"
                },
                ContentTransferEncoding = "7bit",
                Octets = 3028,
                Lines  = 92,
            };

            Assert.IsTrue(text.IsPlain);
            Assert.IsFalse(text.IsHtml);
            Assert.IsFalse(text.IsAttachment);
            Assert.AreEqual("body.txt", text.FileName);
            Assert.AreEqual(expected, text.ToString());
            Assert.IsTrue(BodyPart.TryParse(expected, out body));
            Assert.IsInstanceOf <BodyPartText> (body);

            parsed = (BodyPartText)body;
            Assert.IsTrue(parsed.ContentType.IsMimeType("text", "plain"), "Content-Type did not match.");
            Assert.AreEqual("us-ascii", parsed.ContentType.Charset, "charset param did not match");
            Assert.AreEqual("body.txt", parsed.ContentType.Name, "name param did not match");
            Assert.AreEqual("7bit", parsed.ContentTransferEncoding, "Content-Transfer-Encoding did not match.");
            Assert.AreEqual(3028, parsed.Octets, "Octet count did not match.");
            Assert.AreEqual(92, parsed.Lines, "Line count did not match.");
            Assert.AreEqual(expected, parsed.ToString());
        }
Ejemplo n.º 2
0
        static BodyPartBasic CreateText(string type, string subtype, string partSpecifier, bool attachment)
        {
            var text = new BodyPartText {
                ContentType = CreateContentType(type, subtype, partSpecifier)
            };

            if (attachment)
            {
                text.ContentDisposition = new ContentDisposition(ContentDisposition.Attachment);
            }
            return(text);
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Visit the text-based MIME part entity.
 /// </summary>
 /// <remarks>
 /// Visits the text-based MIME part entity.
 /// </remarks>
 /// <param name="entity">The text-based body part.</param>
 protected internal virtual void VisitBodyPartText(BodyPartText entity)
 {
     VisitBodyPartBasic(entity);
 }
Ejemplo n.º 4
0
		public static BodyPart ParseBody (ImapEngine engine, string path, CancellationToken cancellationToken)
		{
			var token = engine.ReadToken (cancellationToken);

			if (token.Type == ImapTokenType.Nil)
				return null;

			if (token.Type != ImapTokenType.OpenParen)
				throw ImapEngine.UnexpectedToken (token, false);

			token = engine.PeekToken (cancellationToken);

			if (token.Type == ImapTokenType.OpenParen)
				return ParseMultipart (engine, path, null, cancellationToken);

			ContentType type;
			string value;

			if (!ParseContentType (engine, cancellationToken, out type, out value)) {
				// GMail breakage... yay! What we have is a nested multipart with
				// the same boundary as its parent.
				return ParseMultipart (engine, path, value, cancellationToken);
			}

			var id = ReadNStringToken (engine, false, cancellationToken);
			var desc = ReadNStringToken (engine, true, cancellationToken);
			// Note: technically, body-fld-enc, is not allowed to be NIL, but we need to deal with broken servers...
			var enc = ReadNStringToken (engine, false, cancellationToken);
			var octets = ReadNumber (engine, cancellationToken);
			BodyPartBasic body;

			if (type.Matches ("message", "rfc822")) {
				var mesg = new BodyPartMessage ();

				// Note: GMail (and potentially other IMAP servers) will send body-part-basic
				// expressions instead of body-part-msg expressions when they encounter
				// message/rfc822 MIME parts that are illegally encoded using base64 (or
				// quoted-printable?). According to rfc3501, IMAP servers are REQUIRED to
				// send body-part-msg expressions for message/rfc822 parts, however, it is
				// understandable why GMail (and other IMAP servers?) do what they do in this
				// particular case.
				//
				// For examples, see issue #32 and issue #59.
				//
				// The workaround is to check for the expected '(' signifying an envelope token.
				// If we do not get an '(', then we are likely looking at the Content-MD5 token
				// which gets handled below.
				token = engine.PeekToken (cancellationToken);

				if (token.Type == ImapTokenType.OpenParen) {
					mesg.Envelope = ParseEnvelope (engine, cancellationToken);
					mesg.Body = ParseBody (engine, path, cancellationToken);
					mesg.Lines = ReadNumber (engine, cancellationToken);
				}

				body = mesg;
			} else if (type.Matches ("text", "*")) {
				var text = new BodyPartText ();
				text.Lines = ReadNumber (engine, cancellationToken);
				body = text;
			} else {
				body = new BodyPartBasic ();
			}

			body.ContentTransferEncoding = enc;
			body.ContentDescription = desc;
			body.PartSpecifier = path;
			body.ContentType = type;
			body.ContentId = id;
			body.Octets = octets;

			// if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')'
			token = engine.PeekToken (cancellationToken);

			if (token.Type != ImapTokenType.CloseParen) {
				body.ContentMd5 = ReadNStringToken (engine, false, cancellationToken);
				token = engine.PeekToken (cancellationToken);
			}

			if (token.Type != ImapTokenType.CloseParen) {
				body.ContentDisposition = ParseContentDisposition (engine, cancellationToken);
				token = engine.PeekToken (cancellationToken);
			}

			if (token.Type != ImapTokenType.CloseParen) {
				body.ContentLanguage = ParseContentLanguage (engine, cancellationToken);
				token = engine.PeekToken (cancellationToken);
			}

			if (token.Type != ImapTokenType.CloseParen) {
				body.ContentLocation = ParseContentLocation (engine, cancellationToken);
				token = engine.PeekToken (cancellationToken);
			}

			if (token.Type != ImapTokenType.CloseParen)
				SkipBodyExtensions (engine, cancellationToken);

			// read the ')'
			token = engine.ReadToken (cancellationToken);

			if (token.Type != ImapTokenType.CloseParen)
				throw ImapEngine.UnexpectedToken (token, false);

			return body;
		}
Ejemplo n.º 5
0
        async void RenderText(IMailFolder folder, UniqueId uid, BodyPartText bodyPart)
        {
            var entity = await folder.GetBodyPartAsync(uid, bodyPart);

            RenderText((TextPart)entity);
        }
Ejemplo n.º 6
0
        public void TestBodyPartCollection()
        {
            var text = new BodyPartText {
                ContentType = new ContentType("text", "plain"), ContentLocation = new Uri("body", UriKind.Relative)
            };
            var image1 = new BodyPartBasic {
                ContentType = new ContentType("image", "jpeg"), ContentLocation = new Uri("http://localhost/image1.jpg")
            };
            var image2 = new BodyPartBasic {
                ContentType = new ContentType("image", "jpeg"), ContentId = "image2@localhost"
            };
            var list  = new BodyPartCollection();
            var parts = new BodyPart[3];
            int i     = 0;

            Assert.Throws <ArgumentNullException> (() => list.Add(null));
            Assert.Throws <ArgumentNullException> (() => list.Remove(null));
            Assert.Throws <ArgumentNullException> (() => list.Contains(null));
            Assert.Throws <ArgumentNullException> (() => list.IndexOf(null));
            Assert.Throws <ArgumentNullException> (() => list.CopyTo(null, 0));
            Assert.Throws <ArgumentOutOfRangeException> (() => list.CopyTo(parts, -1));
            Assert.Throws <ArgumentOutOfRangeException> (() => { var x = list[0]; });

            Assert.IsFalse(list.IsReadOnly);
            Assert.AreEqual(0, list.Count);

            list.Add(text);
            Assert.AreEqual(1, list.Count);
            Assert.IsTrue(list.Contains(text));
            Assert.IsFalse(list.Contains(image1));
            Assert.AreEqual(0, list.IndexOf(new Uri("body", UriKind.Relative)));
            Assert.AreEqual(-1, list.IndexOf(new Uri("http://localhost/image1.jpg")));
            Assert.AreEqual(-1, list.IndexOf(new Uri("cid:image2@localhost")));
            Assert.AreEqual(text, list[0]);

            list.Add(image1);
            Assert.AreEqual(2, list.Count);
            Assert.IsTrue(list.Contains(text));
            Assert.IsTrue(list.Contains(image1));
            Assert.AreEqual(0, list.IndexOf(new Uri("body", UriKind.Relative)));
            Assert.AreEqual(1, list.IndexOf(new Uri("http://localhost/image1.jpg")));
            Assert.AreEqual(-1, list.IndexOf(new Uri("cid:image2@localhost")));
            Assert.AreEqual(text, list[0]);
            Assert.AreEqual(image1, list[1]);

            Assert.IsTrue(list.Remove(text));
            Assert.AreEqual(1, list.Count);
            Assert.IsFalse(list.Contains(text));
            Assert.IsTrue(list.Contains(image1));
            Assert.AreEqual(-1, list.IndexOf(new Uri("body", UriKind.Relative)));
            Assert.AreEqual(0, list.IndexOf(new Uri("http://localhost/image1.jpg")));
            Assert.AreEqual(-1, list.IndexOf(new Uri("cid:image2@localhost")));
            Assert.AreEqual(image1, list[0]);

            list.Clear();
            Assert.AreEqual(0, list.Count);

            list.Add(text);
            list.Add(image1);
            list.Add(image2);
            list.CopyTo(parts, 0);
            Assert.AreEqual(0, list.IndexOf(new Uri("body", UriKind.Relative)));
            Assert.AreEqual(1, list.IndexOf(new Uri("http://localhost/image1.jpg")));
            Assert.AreEqual(2, list.IndexOf(new Uri("cid:image2@localhost")));

            foreach (var part in list)
            {
                Assert.AreEqual(parts[i++], part);
            }

            i = 0;
            foreach (var part in (IEnumerable)list)
            {
                Assert.AreEqual(parts[i++], part);
            }
        }
Ejemplo n.º 7
0
        public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken(cancellationToken);

            if (token.Type == ImapTokenType.Nil)
            {
                return(null);
            }

            if (token.Type != ImapTokenType.OpenParen)
            {
                throw ImapEngine.UnexpectedToken(token, false);
            }

            token = engine.PeekToken(cancellationToken);

            if (token.Type == ImapTokenType.OpenParen)
            {
                return(ParseMultipart(engine, path, cancellationToken));
            }

            var           type   = ParseContentType(engine, cancellationToken);
            var           id     = ReadNStringToken(engine, false, cancellationToken);
            var           desc   = ReadNStringToken(engine, true, cancellationToken);
            var           enc    = ReadStringToken(engine, cancellationToken);
            var           octets = ReadNumber(engine, cancellationToken);
            BodyPartBasic body;

            if (type.Matches("message", "rfc822"))
            {
                var mesg = new BodyPartMessage();
                mesg.Envelope = ParseEnvelope(engine, cancellationToken);
                mesg.Body     = ParseBody(engine, path, cancellationToken);
                mesg.Lines    = ReadNumber(engine, cancellationToken);
                body          = mesg;
            }
            else if (type.Matches("text", "*"))
            {
                var text = new BodyPartText();
                text.Lines = ReadNumber(engine, cancellationToken);
                body       = text;
            }
            else
            {
                body = new BodyPartBasic();
            }

            body.ContentTransferEncoding = enc;
            body.ContentDescription      = desc;
            body.PartSpecifier           = path;
            body.ContentType             = type;
            body.ContentId = id;
            body.Octets    = octets;

            // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')'
            token = engine.PeekToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentMd5 = ReadNStringToken(engine, false, cancellationToken);
                token           = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentDisposition = ParseContentDisposition(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentLanguage = ParseContentLocation(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentLocation = ReadNStringToken(engine, false, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                SkipBodyExtensions(engine, cancellationToken);
            }

            // read the ')'
            token = engine.ReadToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                throw ImapEngine.UnexpectedToken(token, false);
            }

            return(body);
        }
Ejemplo n.º 8
0
        public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken (cancellationToken);

            if (token.Type == ImapTokenType.Nil)
                return null;

            if (token.Type != ImapTokenType.OpenParen)
                throw ImapEngine.UnexpectedToken (token, false);

            token = engine.PeekToken (cancellationToken);

            if (token.Type == ImapTokenType.OpenParen)
                return ParseMultipart (engine, path, cancellationToken);

            var type = ParseContentType (engine, cancellationToken);
            var id = ReadNStringToken (engine, false, cancellationToken);
            var desc = ReadNStringToken (engine, true, cancellationToken);
            var enc = ReadStringToken (engine, cancellationToken);
            var octets = ReadNumber (engine, cancellationToken);
            BodyPartBasic body;

            if (type.Matches ("message", "rfc822")) {
                var mesg = new BodyPartMessage ();
                mesg.Envelope = ParseEnvelope (engine, cancellationToken);
                mesg.Body = ParseBody (engine, path, cancellationToken);
                mesg.Lines = ReadNumber (engine, cancellationToken);
                body = mesg;
            } else if (type.Matches ("text", "*")) {
                var text = new BodyPartText ();
                text.Lines = ReadNumber (engine, cancellationToken);
                body = text;
            } else {
                body = new BodyPartBasic ();
            }

            body.ContentTransferEncoding = enc;
            body.ContentDescription = desc;
            body.PartSpecifier = path;
            body.ContentType = type;
            body.ContentId = id;
            body.Octets = octets;

            // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')'
            token = engine.PeekToken (cancellationToken);

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentMd5 = ReadNStringToken (engine, false, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentDisposition = ParseContentDisposition (engine, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentLanguage = ParseContentLocation (engine, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentLocation = ReadNStringToken (engine, false, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
                SkipBodyExtensions (engine, cancellationToken);

            // read the ')'
            token = engine.ReadToken (cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
                throw ImapEngine.UnexpectedToken (token, false);

            return body;
        }
Ejemplo n.º 9
0
        public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken(cancellationToken);

            if (token.Type == ImapTokenType.Nil)
            {
                return(null);
            }

            if (token.Type != ImapTokenType.OpenParen)
            {
                throw ImapEngine.UnexpectedToken(token, false);
            }

            token = engine.PeekToken(cancellationToken);

            if (token.Type == ImapTokenType.OpenParen)
            {
                return(ParseMultipart(engine, path, cancellationToken));
            }

            var type = ParseContentType(engine, cancellationToken);
            var id   = ReadNStringToken(engine, false, cancellationToken);
            var desc = ReadNStringToken(engine, true, cancellationToken);
            // Note: technically, body-fld-enc, is not allowed to be NIL, but we need to deal with broken servers...
            var           enc    = ReadNStringToken(engine, false, cancellationToken);
            var           octets = ReadNumber(engine, cancellationToken);
            BodyPartBasic body;

            if (type.Matches("message", "rfc822"))
            {
                var mesg = new BodyPartMessage();

                // Note: GMail's support for message/rfc822 body parts is broken. Essentially,
                // GMail treats message/rfc822 parts as if they were basic body parts.
                //
                // For examples, see issue #32 and issue #59.
                //
                // The workaround is to check for the expected '(' signifying an envelope token.
                // If we do not get an '(', then we are likely looking at the Content-MD5 token
                // which gets handled below.
                token = engine.PeekToken(cancellationToken);

                if (!engine.IsGMail || token.Type == ImapTokenType.OpenParen)
                {
                    mesg.Envelope = ParseEnvelope(engine, cancellationToken);
                    mesg.Body     = ParseBody(engine, path, cancellationToken);
                    mesg.Lines    = ReadNumber(engine, cancellationToken);
                }

                body = mesg;
            }
            else if (type.Matches("text", "*"))
            {
                var text = new BodyPartText();
                text.Lines = ReadNumber(engine, cancellationToken);
                body       = text;
            }
            else
            {
                body = new BodyPartBasic();
            }

            body.ContentTransferEncoding = enc;
            body.ContentDescription      = desc;
            body.PartSpecifier           = path;
            body.ContentType             = type;
            body.ContentId = id;
            body.Octets    = octets;

            // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')'
            token = engine.PeekToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentMd5 = ReadNStringToken(engine, false, cancellationToken);
                token           = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentDisposition = ParseContentDisposition(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentLanguage = ParseContentLanguage(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentLocation = ParseContentLocation(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                SkipBodyExtensions(engine, cancellationToken);
            }

            // read the ')'
            token = engine.ReadToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                throw ImapEngine.UnexpectedToken(token, false);
            }

            return(body);
        }
Ejemplo n.º 10
0
        async Task <string> RenderTextAsync(IMailFolder folder, UniqueId uid, BodyPartText bodyPart)
        {
            var entity = await folder.GetBodyPartAsync(uid, bodyPart);

            return(RenderText((TextPart)entity));
        }
Ejemplo n.º 11
0
        public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken (cancellationToken);

            if (token.Type == ImapTokenType.Nil)
                return null;

            if (token.Type != ImapTokenType.OpenParen)
                throw ImapEngine.UnexpectedToken (token, false);

            token = engine.PeekToken (cancellationToken);

            if (token.Type == ImapTokenType.OpenParen)
                return ParseMultipart (engine, path, cancellationToken);

            var type = ParseContentType (engine, cancellationToken);
            var id = ReadNStringToken (engine, false, cancellationToken);
            var desc = ReadNStringToken (engine, true, cancellationToken);
            // Note: technically, body-fld-enc, is not allowed to be NIL, but we need to deal with broken servers...
            var enc = ReadNStringToken (engine, false, cancellationToken);
            var octets = ReadNumber (engine, cancellationToken);
            BodyPartBasic body;

            if (type.Matches ("message", "rfc822")) {
                var mesg = new BodyPartMessage ();

                // Note: GMail's support for message/rfc822 body parts is broken. Essentially,
                // GMail treats message/rfc822 parts as if they were basic body parts.
                //
                // For examples, see issue #32 and issue #59.
                //
                // The workaround is to check for the expected '(' signifying an envelope token.
                // If we do not get an '(', then we are likely looking at the Content-MD5 token
                // which gets handled below.
                token = engine.PeekToken (cancellationToken);

                if (!engine.IsGMail || token.Type == ImapTokenType.OpenParen) {
                    mesg.Envelope = ParseEnvelope (engine, cancellationToken);
                    mesg.Body = ParseBody (engine, path, cancellationToken);
                    mesg.Lines = ReadNumber (engine, cancellationToken);
                }

                body = mesg;
            } else if (type.Matches ("text", "*")) {
                var text = new BodyPartText ();
                text.Lines = ReadNumber (engine, cancellationToken);
                body = text;
            } else {
                body = new BodyPartBasic ();
            }

            body.ContentTransferEncoding = enc;
            body.ContentDescription = desc;
            body.PartSpecifier = path;
            body.ContentType = type;
            body.ContentId = id;
            body.Octets = octets;

            // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')'
            token = engine.PeekToken (cancellationToken);

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentMd5 = ReadNStringToken (engine, false, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentDisposition = ParseContentDisposition (engine, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentLanguage = ParseContentLanguage (engine, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen) {
                body.ContentLocation = ParseContentLocation (engine, cancellationToken);
                token = engine.PeekToken (cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
                SkipBodyExtensions (engine, cancellationToken);

            // read the ')'
            token = engine.ReadToken (cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
                throw ImapEngine.UnexpectedToken (token, false);

            return body;
        }
Ejemplo n.º 12
0
        async void RenderRelated(IMailFolder folder, UniqueId uid, BodyPartMultipart related)
        {
            var          start = related.ContentType.Parameters["start"];
            BodyPartText root  = null;

            if (!string.IsNullOrEmpty(start))
            {
                // if the 'start' parameter is set, it overrides the default behavior of using the first
                // body part as the main document.
                root = related.BodyParts.OfType <BodyPartText> ().FirstOrDefault(x => x.ContentId == start);
            }
            else if (related.BodyParts.Count > 0)
            {
                // this will generally either be a text/html part (which is what we are looking for) or a multipart/alternative
                var multipart = related.BodyParts[0] as BodyPartMultipart;

                if (multipart != null)
                {
                    if (multipart.ContentType.Matches("multipart", "alternative") && multipart.BodyParts.Count > 0)
                    {
                        // find the last text/html part (which will be the closest to what the sender saw in their WYSIWYG editor)
                        // or, failing that, the last text part.
                        for (int i = multipart.BodyParts.Count; i > 0; i--)
                        {
                            var bodyPart = multipart.BodyParts[i - 1] as BodyPartText;

                            if (bodyPart == null)
                            {
                                continue;
                            }

                            if (bodyPart.ContentType.Matches("text", "html"))
                            {
                                root = bodyPart;
                                break;
                            }

                            if (root == null)
                            {
                                root = bodyPart;
                            }
                        }
                    }
                }
                else
                {
                    root = related.BodyParts[0] as BodyPartText;
                }
            }

            if (root == null)
            {
                return;
            }

            var text = await folder.GetBodyPartAsync(uid, root) as TextPart;

            if (text != null && text.ContentType.Matches("text", "html"))
            {
                var      doc   = new HtmlAgilityPack.HtmlDocument();
                var      saved = new Dictionary <MimePart, string> ();
                TextPart html;

                doc.LoadHtml(text.Text);

                // find references to related MIME parts and replace them with links to links to the saved attachments
                foreach (var img in doc.DocumentNode.SelectNodes("//img[@src]"))
                {
                    var src = img.Attributes["src"];
                    int index;
                    Uri uri;

                    if (src == null || src.Value == null)
                    {
                        continue;
                    }

                    // parse the <img src=...> attribute value into a Uri
                    if (Uri.IsWellFormedUriString(src.Value, UriKind.Absolute))
                    {
                        uri = new Uri(src.Value, UriKind.Absolute);
                    }
                    else
                    {
                        uri = new Uri(src.Value, UriKind.Relative);
                    }

                    // locate the index of the attachment within the multipart/related (if it exists)
                    if ((index = related.BodyParts.IndexOf(uri)) != -1)
                    {
                        var bodyPart = related.BodyParts[index] as BodyPartBasic;

                        if (bodyPart == null)
                        {
                            // the body part is not a basic leaf part (IOW it's a multipart or message-part)
                            continue;
                        }

                        var attachment = await folder.GetBodyPartAsync(uid, bodyPart) as MimePart;

                        // make sure the referenced part is a MimePart (as opposed to another Multipart or MessagePart)
                        if (attachment == null)
                        {
                            continue;
                        }

                        string fileName;

                        // save the attachment (if we haven't already saved it)
                        if (!saved.TryGetValue(attachment, out fileName))
                        {
                            fileName = attachment.FileName;

                            if (string.IsNullOrEmpty(fileName))
                            {
                                fileName = Guid.NewGuid().ToString();
                            }

                            if (!Directory.Exists(uid.ToString()))
                            {
                                Directory.CreateDirectory(uid.ToString());
                            }

                            fileName = Path.Combine(uid.ToString(), fileName);

                            using (var stream = File.Create(fileName))
                                attachment.ContentObject.DecodeTo(stream);

                            saved.Add(attachment, fileName);
                        }

                        // replace the <img src=...> value with the local file name
                        src.Value = "file://" + Path.GetFullPath(fileName);
                    }
                }

                if (saved.Count > 0)
                {
                    // we had to make some modifications to the original html part, so create a new
                    // (temporary) text/html part to render
                    html = new TextPart("html");
                    using (var writer = new StringWriter()) {
                        doc.Save(writer);

                        html.Text = writer.GetStringBuilder().ToString();
                    }
                }
                else
                {
                    html = text;
                }

                RenderText(html);
            }
            else if (text != null)
            {
                RenderText(text);
            }
        }
Ejemplo n.º 13
0
        private static async void RenderText(IMailFolder folder, UniqueId uid, BodyPartText bodyPart, WebBrowserEditabil pWebBrowser)
        {
            var entity = await folder.GetBodyPartAsync(uid, bodyPart);

            RenderText((TextPart)entity, pWebBrowser);
        }
Ejemplo n.º 14
0
		/// <summary>
		/// Visit the text-based MIME part entity.
		/// </summary>
		/// <remarks>
		/// Visits the text-based MIME part entity.
		/// </remarks>
		/// <param name="entity">The text-based body part.</param>
		protected internal virtual void VisitBodyPartText (BodyPartText entity)
		{
			VisitBodyPartBasic (entity);
		}
Ejemplo n.º 15
0
        public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken(cancellationToken);

            if (token.Type == ImapTokenType.Nil)
            {
                return(null);
            }

            if (token.Type != ImapTokenType.OpenParen)
            {
                throw ImapEngine.UnexpectedToken(token, false);
            }

            token = engine.PeekToken(cancellationToken);

            if (token.Type == ImapTokenType.OpenParen)
            {
                return(ParseMultipart(engine, path, cancellationToken));
            }

            var type = ParseContentType(engine, cancellationToken);
            var id   = ReadNStringToken(engine, false, cancellationToken);
            var desc = ReadNStringToken(engine, true, cancellationToken);
            // Note: technically, body-fld-enc, is not allowed to be NIL, but we need to deal with broken servers...
            var           enc    = ReadNStringToken(engine, false, cancellationToken);
            var           octets = ReadNumber(engine, cancellationToken);
            BodyPartBasic body;

            if (type.Matches("message", "rfc822"))
            {
                var mesg = new BodyPartMessage();

                // Note: GMail (and potentially other IMAP servers) will send body-part-basic
                // expressions instead of body-part-msg expressions when they encounter
                // message/rfc822 MIME parts that are illegally encoded using base64 (or
                // quoted-printable?). According to rfc3501, IMAP servers are REQUIRED to
                // send body-part-msg expressions for message/rfc822 parts, however, it is
                // understandable why GMail (and other IMAP servers?) do what they do in this
                // particular case.
                //
                // For examples, see issue #32 and issue #59.
                //
                // The workaround is to check for the expected '(' signifying an envelope token.
                // If we do not get an '(', then we are likely looking at the Content-MD5 token
                // which gets handled below.
                token = engine.PeekToken(cancellationToken);

                if (token.Type == ImapTokenType.OpenParen)
                {
                    mesg.Envelope = ParseEnvelope(engine, cancellationToken);
                    mesg.Body     = ParseBody(engine, path, cancellationToken);
                    mesg.Lines    = ReadNumber(engine, cancellationToken);
                }

                body = mesg;
            }
            else if (type.Matches("text", "*"))
            {
                var text = new BodyPartText();
                text.Lines = ReadNumber(engine, cancellationToken);
                body       = text;
            }
            else
            {
                body = new BodyPartBasic();
            }

            body.ContentTransferEncoding = enc;
            body.ContentDescription      = desc;
            body.PartSpecifier           = path;
            body.ContentType             = type;
            body.ContentId = id;
            body.Octets    = octets;

            // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')'
            token = engine.PeekToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentMd5 = ReadNStringToken(engine, false, cancellationToken);
                token           = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentDisposition = ParseContentDisposition(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentLanguage = ParseContentLanguage(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                body.ContentLocation = ParseContentLocation(engine, cancellationToken);
                token = engine.PeekToken(cancellationToken);
            }

            if (token.Type != ImapTokenType.CloseParen)
            {
                SkipBodyExtensions(engine, cancellationToken);
            }

            // read the ')'
            token = engine.ReadToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                throw ImapEngine.UnexpectedToken(token, false);
            }

            return(body);
        }