Пример #1
0
        /// <summary>
        /// Parses an untagged ID response.
        /// </summary>
        /// <param name="engine">The IMAP engine.</param>
        /// <param name="ic">The IMAP command.</param>
        /// <param name="index">The index.</param>
        public static void ParseImplementation(ImapEngine engine, ImapCommand ic, int index)
        {
            var token          = engine.ReadToken(ic.CancellationToken);
            var implementation = new ImapImplementation();

            ic.UserData = implementation;

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

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

            token = engine.PeekToken(ic.CancellationToken);

            while (token.Type != ImapTokenType.CloseParen)
            {
                var property = ImapUtils.ReadStringToken(engine, ic.CancellationToken);
                var value    = ImapUtils.ReadNStringToken(engine, false, ic.CancellationToken);

                implementation.Properties[property] = value;

                token = engine.PeekToken(ic.CancellationToken);
            }

            // read the ')' token
            engine.ReadToken(ic.CancellationToken);
        }
Пример #2
0
        static void ParseParameterList(StringBuilder builder, ImapEngine engine, CancellationToken cancellationToken)
        {
            ImapToken token;

            do
            {
                token = engine.PeekToken(cancellationToken);

                if (token.Type == ImapTokenType.CloseParen)
                {
                    break;
                }

                var name  = ReadStringToken(engine, cancellationToken);
                var value = ReadStringToken(engine, cancellationToken);

                builder.Append("; ").Append(name).Append('=');

                if (NeedsQuoting(value))
                {
                    builder.Append(MimeUtils.Quote(value));
                }
                else
                {
                    builder.Append(value);
                }
            } while (true);

            // read the ')'
            engine.ReadToken(cancellationToken);
        }
Пример #3
0
        /// <summary>
        /// Parses the threads.
        /// </summary>
        /// <returns>The threads.</returns>
        /// <param name="engine">The IMAP engine.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        public static MessageThread[] ParseThreads(ImapEngine engine, CancellationToken cancellationToken)
        {
            var       threads = new List <MessageThread> ();
            ImapToken token;

            do
            {
                token = engine.PeekToken(cancellationToken);

                if (token.Type == ImapTokenType.Eoln)
                {
                    break;
                }

                token = engine.ReadToken(cancellationToken);

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

                threads.Add(ParseThread(engine, cancellationToken));
            } while (true);

            return(threads.ToArray());
        }
Пример #4
0
        static void ParseParameterList(StringBuilder builder, ImapEngine engine, CancellationToken cancellationToken)
        {
            ImapToken token;

            do {
                token = engine.PeekToken (cancellationToken);

                if (token.Type == ImapTokenType.CloseParen)
                    break;

                var name = ReadStringToken (engine, cancellationToken);

                // Note: technically, the value should also be a 'string' token and not an 'nstring',
                // but issue #124 reveals a server that is sending NIL for boundary values.
                var value = ReadNStringToken (engine, false, cancellationToken) ?? string.Empty;

                builder.Append ("; ").Append (name).Append ('=');

                if (NeedsQuoting (value))
                    builder.Append (MimeUtils.Quote (value));
                else
                    builder.Append (value);
            } while (true);

            // read the ')'
            engine.ReadToken (cancellationToken);
        }
Пример #5
0
        static void SkipBodyExtensions(ImapEngine engine, CancellationToken cancellationToken)
        {
            var token = engine.ReadToken (cancellationToken);

            switch (token.Type) {
            case ImapTokenType.OpenParen:
                do {
                    token = engine.PeekToken (cancellationToken);

                    if (token.Type == ImapTokenType.CloseParen)
                        break;

                    SkipBodyExtensions (engine, cancellationToken);
                } while (true);

                // read the ')'
                engine.ReadToken (cancellationToken);
                break;
            case ImapTokenType.Literal:
                engine.ReadLiteral (cancellationToken);
                break;
            case ImapTokenType.QString:
            case ImapTokenType.Atom:
            case ImapTokenType.Nil:
                break;
            default:
                throw ImapEngine.UnexpectedToken (token, false);
            }
        }
Пример #6
0
        static string[] ParseContentLocation(ImapEngine engine, CancellationToken cancellationToken)
        {
            var    token     = engine.ReadToken(cancellationToken);
            var    languages = new List <string> ();
            string language;

            switch (token.Type)
            {
            case ImapTokenType.Literal:
                language = engine.ReadLiteral(cancellationToken);
                languages.Add(language);
                break;

            case ImapTokenType.QString:
            case ImapTokenType.Atom:
                language = (string)token.Value;
                languages.Add(language);
                break;

            case ImapTokenType.Nil:
                return(null);

            case ImapTokenType.OpenParen:
                do
                {
                    token = engine.PeekToken(cancellationToken);

                    if (token.Type == ImapTokenType.CloseParen)
                    {
                        break;
                    }

                    language = ReadStringToken(engine, cancellationToken);
                    languages.Add(language);
                } while (true);

                // read the ')'
                engine.ReadToken(cancellationToken);
                break;

            default:
                throw ImapEngine.UnexpectedToken(token, false);
            }

            return(languages.ToArray());
        }
Пример #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);
        }
Пример #8
0
        static BodyPart ParseMultipart(ImapEngine engine, string path, CancellationToken cancellationToken)
        {
            var       prefix = path.Length > 0 ? path + "." : string.Empty;
            var       body   = new BodyPartMultipart();
            ImapToken token;
            int       index = 1;

            do
            {
                body.BodyParts.Add(ParseBody(engine, prefix + index, cancellationToken));
                token = engine.PeekToken(cancellationToken);
                index++;
            } while (token.Type == ImapTokenType.OpenParen);

            var subtype = ReadStringToken(engine, cancellationToken);

            body.ContentType   = new ContentType("multipart", subtype);
            body.PartSpecifier = path;

            token = engine.PeekToken(cancellationToken);

            if (token.Type != ImapTokenType.CloseParen)
            {
                token = engine.ReadToken(cancellationToken);

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

                var         builder = new StringBuilder();
                ContentType contentType;

                builder.AppendFormat("{0}/{1}", body.ContentType.MediaType, body.ContentType.MediaSubtype);
                ParseParameterList(builder, engine, cancellationToken);

                if (ContentType.TryParse(builder.ToString(), out contentType))
                {
                    body.ContentType = contentType;
                }

                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);
        }
Пример #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);
        }
Пример #10
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);
        }