Пример #1
0
        /// <summary>
        /// Sends the next part of the command to the server.
        /// </summary>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        /// <exception cref="ImapProtocolException">
        /// An IMAP protocol error occurred.
        /// </exception>
        public bool Step()
        {
            var       supportsLiteralPlus = (Engine.Capabilities & ImapCapabilities.LiteralPlus) != 0;
            int       timeout             = Engine.Stream.CanTimeout ? Engine.Stream.ReadTimeout : -1;
            var       idle   = UserData as ImapIdleContext;
            var       result = ImapCommandResult.None;
            ImapToken token;

            // construct and write the command tag if this is the initial state
            if (current == 0)
            {
                Tag = string.Format("{0}{1:D8}", Engine.TagPrefix, Engine.Tag++);

                var buf = Encoding.ASCII.GetBytes(Tag + " ");
                Engine.Stream.Write(buf, 0, buf.Length, CancellationToken);
            }

            do
            {
                var command = parts[current].Command;

                Engine.Stream.Write(command, 0, command.Length, CancellationToken);

                // if the server doesn't support LITERAL+, we'll need to wait for a "+" response
                // before writing out the any literals...
                if (!supportsLiteralPlus || parts[current].Literal == null)
                {
                    break;
                }

                // otherwise, we can write out any and all literal tokens we have...
                parts[current].Literal.WriteTo(Engine.Stream, CancellationToken);

                if (current + 1 >= parts.Count)
                {
                    break;
                }

                current++;
            } while (true);

            Engine.Stream.Flush();

            // now we need to read the response...
            do
            {
                if (Engine.State == ImapEngineState.Idle)
                {
                    try {
                        if (Engine.Stream.CanTimeout)
                        {
                            Engine.Stream.ReadTimeout = -1;
                        }

                        token = Engine.ReadToken(idle.LinkedToken);

                        if (Engine.Stream.CanTimeout)
                        {
                            Engine.Stream.ReadTimeout = timeout;
                        }
                    } catch (OperationCanceledException) {
                        if (Engine.Stream.CanTimeout)
                        {
                            Engine.Stream.ReadTimeout = timeout;
                        }

                        if (idle.IsCancellationRequested)
                        {
                            throw;
                        }

                        Engine.Stream.IsConnected = true;

                        token = Engine.ReadToken(CancellationToken);
                    }
                }
                else
                {
                    token = Engine.ReadToken(CancellationToken);
                }

                if (token.Type == ImapTokenType.Plus)
                {
                    // we've gotten a continuation response from the server
                    var text = Engine.ReadLine(CancellationToken).Trim();

                    // if we've got a Literal pending, the '+' means we can send it now...
                    if (!supportsLiteralPlus && parts[current].Literal != null)
                    {
                        parts[current].Literal.WriteTo(Engine.Stream, CancellationToken);
                        break;
                    }

                    Debug.Assert(ContinuationHandler != null, "The ImapCommand's ContinuationHandler is null");

                    ContinuationHandler(Engine, this, text);
                }
                else if (token.Type == ImapTokenType.Asterisk)
                {
                    // we got an untagged response, let the engine handle this...
                    Engine.ProcessUntaggedResponse(CancellationToken);
                }
                else if (token.Type == ImapTokenType.Atom && (string)token.Value == Tag)
                {
                    // the next token should be "OK", "NO", or "BAD"
                    token = Engine.ReadToken(CancellationToken);

                    if (token.Type == ImapTokenType.Atom)
                    {
                        string atom = (string)token.Value;

                        switch (atom)
                        {
                        case "BAD": result = ImapCommandResult.Bad; break;

                        case "OK": result = ImapCommandResult.Ok; break;

                        case "NO": result = ImapCommandResult.No; break;

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

                        token = Engine.ReadToken(CancellationToken);
                        if (token.Type == ImapTokenType.OpenBracket)
                        {
                            var code = Engine.ParseResponseCode(CancellationToken);
                            RespCodes.Add(code);
                            break;
                        }

                        if (token.Type != ImapTokenType.Eoln)
                        {
                            // consume the rest of the line...
                            Engine.ReadLine(CancellationToken);
                            break;
                        }
                    }
                    else
                    {
                        // looks like we didn't get an "OK", "NO", or "BAD"...
                        throw ImapEngine.UnexpectedToken(token, false);
                    }
                }
                else if (token.Type == ImapTokenType.OpenBracket)
                {
                    // Note: this is a work-around for broken IMAP servers like Office365.com that
                    // return RESP-CODES that are not preceded by "* OK " such as the example in
                    // issue #115 (https://github.com/jstedfast/MailKit/issues/115).
                    var code = Engine.ParseResponseCode(CancellationToken);
                    RespCodes.Add(code);
                }
                else
                {
                    // no clue what we got...
                    throw ImapEngine.UnexpectedToken(token, false);
                }
            } while (true);

            // the status should always be Active at this point, but just to be sure...
            if (Status == ImapCommandStatus.Active)
            {
                current++;

                if (current >= parts.Count || result != ImapCommandResult.None)
                {
                    Status = ImapCommandStatus.Complete;
                    Result = result;
                    return(false);
                }
            }

            return(true);
        }
Пример #2
0
        /// <summary>
        /// Sends the next part of the command to the server.
        /// </summary>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        /// <exception cref="ImapProtocolException">
        /// An IMAP protocol error occurred.
        /// </exception>
        public bool Step()
        {
            var result = ImapCommandResult.None;

            CancellationToken.ThrowIfCancellationRequested();

            if (current == 0)
            {
                Tag = string.Format("{0}{1:D8}", Engine.TagPrefix, Engine.Tag++);

                var buf = Encoding.ASCII.GetBytes(Tag + " ");
                Engine.Stream.Write(buf, 0, buf.Length);
            }

            Engine.Stream.Write(parts[current].Command, 0, parts[current].Command.Length);
            Engine.Stream.Flush();

            // now we need to read the response...
            do
            {
                var token = Engine.ReadToken(CancellationToken);

                if (token.Type == ImapTokenType.Plus)
                {
                    // we've gotten a continuation response from the server
                    var text = Engine.ReadLine(CancellationToken).Trim();

                    // if we've got a Literal pending, the '+' means we can send it now...
                    if (parts[current].Literal != null)
                    {
                        parts[current].Literal.WriteTo(Engine.Stream, CancellationToken);
                        break;
                    }

                    Debug.Assert(ContinuationHandler != null, "The ImapCommand's ContinuationHandler is null");

                    ContinuationHandler(Engine, this, text);
                }
                else if (token.Type == ImapTokenType.Asterisk)
                {
                    // we got an untagged response, let the engine handle this...
                    Engine.ProcessUntaggedResponse(CancellationToken);
                }
                else if (token.Type == ImapTokenType.Atom && (string)token.Value == Tag)
                {
                    // the next token should be "OK", "NO", or "BAD"
                    token = Engine.ReadToken(CancellationToken);

                    if (token.Type == ImapTokenType.Atom)
                    {
                        string atom = (string)token.Value;

                        switch (atom)
                        {
                        case "BAD": result = ImapCommandResult.Bad; break;

                        case "OK": result = ImapCommandResult.Ok; break;

                        case "NO": result = ImapCommandResult.No; break;
                        }

                        if (result == ImapCommandResult.None)
                        {
                            throw ImapEngine.UnexpectedToken(token, false);
                        }

                        token = Engine.Stream.ReadToken(CancellationToken);
                        if (token.Type == ImapTokenType.OpenBracket)
                        {
                            var code = Engine.ParseResponseCode(CancellationToken);
                            RespCodes.Add(code);
                            break;
                        }

                        if (token.Type != ImapTokenType.Eoln)
                        {
                            // consume the rest of the line...
                            Engine.ReadLine(CancellationToken);
                            break;
                        }
                    }
                    else
                    {
                        // looks like we didn't get an "OK", "NO", or "BAD"...
                        throw ImapEngine.UnexpectedToken(token, false);
                    }
                }
                else
                {
                    // no clue what we got...
                    throw ImapEngine.UnexpectedToken(token, false);
                }
            } while (true);

            // the status should always be Active at this point, but just to be sure...
            if (Status == ImapCommandStatus.Active)
            {
                current++;

                if (current == parts.Count || result != ImapCommandResult.None)
                {
                    Status = ImapCommandStatus.Complete;
                    Result = result;
                    return(false);
                }
            }

            return(true);
        }