Exemple #1
0
 /// <summary>
 /// Remove the specified command from the state.
 /// </summary>
 /// <param name="state">The SMTP state to remove the command from.</param>
 /// <param name="command">The command to remove from the state.</param>
 void RemoveCommand(SmtpState state, string command)
 {
     if (_stateTable[state].Actions.ContainsKey(command))
     {
         _stateTable[state].Actions.Remove(command);
     }
 }
            //internal System.IO.MemoryStream DataStream { get { return this.dataStream; } set { this.dataStream = value; }  }

            internal SmtpSession() : base(DATA_TERMINATOR, 2)
            {
                this.state  = SmtpState.None;
                this.rcptTo = new List <string>();
                //this.dataStream = new System.IO.MemoryStream();
                //this.asciiEncoding = new System.Text.ASCIIEncoding();
            }
            /*
             * internal void AddData(string dataString) {
             *  byte[] data = asciiEncoding.GetBytes(dataString);
             *  this.AddData(data, 0, data.Length);
             * }
             */
            /*
             * internal void AddData(byte[] buffer, int offset, int count) {
             *  List<byte> readBytes;
             *
             *  long terminatorIndex = Utils.KnuthMorrisPratt.ReadTo(DATA_TERMINATOR, buffer, offset, out readBytes);
             *  //terminator might be split in between two packets
             *  if (terminatorIndex == -1 && this.dataStream.Length > 0) {
             *      int oldBytesToRead = Math.Min(DATA_TERMINATOR.Length-1, (int)dataStream.Length);
             *      byte[] oldBufferTail = new byte[oldBytesToRead];
             *      this.dataStream.Seek(this.dataStream.Length - oldBytesToRead, System.IO.SeekOrigin.Begin);
             *      int oldBytesRead = this.dataStream.Read(oldBufferTail, 0, oldBytesToRead);
             *      byte[] tempBuffer = new byte[oldBytesRead + buffer.Length - offset];
             *      Array.Copy(oldBufferTail, 0, tempBuffer, 0, oldBytesRead);
             *      Array.Copy(buffer, offset, tempBuffer, oldBytesRead, buffer.Length - offset);
             *      long tempTerminatorIndex = Utils.KnuthMorrisPratt.ReadTo(DATA_TERMINATOR, tempBuffer, 0, out readBytes);
             *      if (tempTerminatorIndex >= 0) {
             *          count = (int)tempTerminatorIndex - oldBytesRead + 2;
             *          this.state = SmtpState.Footer;
             *      }
             *  }
             *  else if(terminatorIndex >= 0) {
             *      //terminator was found
             *
             *      //the final <cr><lf>.<cr><lf> will not included, but let's at least add one <cr><lf> at the end
             *      count = (int)terminatorIndex-offset+2; //"+2" adds the <cr><lf>
             *      //offset = 0;
             *      this.state = SmtpState.Footer;
             *  }
             *  if (count > 0) {
             *      this.dataStream.Seek(0, System.IO.SeekOrigin.End);
             *      this.dataStream.Write(buffer, offset, count);
             *  }
             * }*/

            internal new void AddData(byte[] buffer, int offset, int count)
            {
                base.AddData(buffer, offset, count);
                if (base.TerminatorFound)
                {
                    this.state = SmtpState.Footer;
                }
            }
Exemple #4
0
        public SmtpSession(SmtpServer server, Socket s)
        {
            _server     = server;
            _serverName = GetServerName(s);

            var ascii = Encoding.ASCII;

            ReplyGreeting              = ascii.GetBytes(string.Format("220 {0} ESMTP ready.\r\n", _serverName));
            ReplyOk                    = ascii.GetBytes("250 OK\r\n");
            ReplyEhlo                  = ascii.GetBytes(string.Format("250-{0}\r\n250-8BITMIME\r\n250 SIZE {0}\r\n", _serverName, MaximumMessageSize));
            ReplyHelo                  = ascii.GetBytes(string.Format("250 {0}\r\n", _serverName));
            ReplySyntaxErrorRset       = ascii.GetBytes("501 RSET syntax error\r\n");
            ReplySyntaxErrorEhlo       = ascii.GetBytes("501 EHLO syntax error\r\n");
            ReplySyntaxErrorHelo       = ascii.GetBytes("501 HELO syntax error\r\n");
            ReplySyntaxErrorMail       = ascii.GetBytes("501 MAIL syntax error\r\n");
            ReplySyntaxErrorRcpt       = ascii.GetBytes("501 RCPT syntax error\r\n");
            ReplySyntaxErrorData       = ascii.GetBytes("501 DATA syntax error\r\n");
            ReplySyntaxErrorQuit       = ascii.GetBytes("501 QUIT syntax error\r\n");
            ReplyCommandNotImplemented = ascii.GetBytes("502 Command not implemented\r\n");
            ReplyUnknownCommand        = ascii.GetBytes("500 Unknown command\r\n");
            ReplyBadSequence           = ascii.GetBytes("503 Bad sequence of command\r\n");
            ReplyHelp                  = ascii.GetBytes("211 You don't need help\r\n");
            ReplyStartMail             = ascii.GetBytes("354 Start mail input; end with <CRLF>.<CRLF>\r\n");
            ReplyBye                   = ascii.GetBytes("221 Bye\r\n");
            ReplyNoSuchUserHere        = ascii.GetBytes("550 No such user here\r\n");
            ReplyMessageSizeTooBig     = ascii.GetBytes("552 Message size exceeds maximum permitted\r\n");

            _lock   = new object();
            _socket = s;
            _socket.ReceiveBufferSize = 8192;
            _socket.SendBufferSize    = 8192;
            _utcCreationTime          = DateTime.UtcNow;

            _state              = SmtpState.WaitingForHelo;
            _isAborting         = false;
            _receiveBuffer      = new byte[_socket.ReceiveBufferSize + 128];
            _bufferedData       = new byte[_socket.ReceiveBufferSize + 128];
            _bufferedDataLength = 0;
            ResetMailInfo();
            _isAlive     = true;
            _emptyBuffer = new ArraySegment <byte>(Bytes.Empty);
            Greet();
            Receive();
        }
            /// <summary>
            /// Advances the enumerator to the next command in the stream.
            /// </summary>
            /// <param name="context">The session context to use for making session based transitions.</param>
            /// <param name="tokenEnumerator">The token enumerator to accept the command from.</param>
            /// <param name="command">The command that is defined within the token enumerator.</param>
            /// <param name="errorResponse">The error that indicates why the command could not be made.</param>
            /// <returns>true if a valid command was found, false if not.</returns>
            public bool TryAccept(SmtpSessionContext context, TokenEnumerator tokenEnumerator, out SmtpCommand command, out SmtpResponse errorResponse)
            {
                if (_states[_current].Transitions.TryGetValue(tokenEnumerator.Peek().Text, out StateTransition transition) == false)
                {
                    var response = $"expected {String.Join("/", _states[_current].Transitions.Keys)}";

                    command       = null;
                    errorResponse = new SmtpResponse(SmtpReplyCode.SyntaxError, response);

                    return(false);
                }

                if (transition.Delegate(tokenEnumerator, out command, out errorResponse) == false)
                {
                    return(false);
                }

                _current = transition.Transition(context);

                return(true);
            }
            internal void AddData(byte[] buffer, int offset, int count)
            {
                List <byte> readBytes;

                long terminatorIndex = Utils.KnuthMorrisPratt.ReadTo(DATA_TERMINATOR, buffer, offset, out readBytes);

                //terminator might be split in between two packets
                if (terminatorIndex == -1 && this.dataStream.Length > 0)
                {
                    int    oldBytesToRead = Math.Min(DATA_TERMINATOR.Length - 1, (int)dataStream.Length);
                    byte[] oldBufferTail  = new byte[oldBytesToRead];
                    this.dataStream.Seek(this.dataStream.Length - oldBytesToRead, System.IO.SeekOrigin.Begin);
                    int    oldBytesRead = this.dataStream.Read(oldBufferTail, 0, oldBytesToRead);
                    byte[] tempBuffer   = new byte[oldBytesRead + buffer.Length - offset];
                    Array.Copy(oldBufferTail, 0, tempBuffer, 0, oldBytesRead);
                    Array.Copy(buffer, offset, tempBuffer, oldBytesRead, buffer.Length - offset);
                    long tempTerminatorIndex = Utils.KnuthMorrisPratt.ReadTo(DATA_TERMINATOR, tempBuffer, 0, out readBytes);
                    if (tempTerminatorIndex >= 0)
                    {
                        count      = (int)tempTerminatorIndex - oldBytesRead + 2;
                        this.state = SmtpState.Footer;
                    }
                }
                else if (terminatorIndex >= 0)
                {
                    //terminator was found

                    //the final <cr><lf>.<cr><lf> will not included, but let's at least add one <cr><lf> at the end
                    count = (int)terminatorIndex - offset + 2; //"+2" adds the <cr><lf>
                    //offset = 0;
                    this.state = SmtpState.Footer;
                }
                if (count > 0)
                {
                    this.dataStream.Seek(0, System.IO.SeekOrigin.End);
                    this.dataStream.Write(buffer, offset, count);
                }
            }
Exemple #7
0
 /// <summary>
 /// Sets the initial state.
 /// </summary>
 /// <param name="stateId">The ID of the initial state.</param>
 public void Initialize(SmtpState stateId)
 {
     _state = _states[stateId];
 }
Exemple #8
0
		/// <summary> 
		/// Create a new SMTP client request.
		/// </summary>
		/// <param name="actionType">type of action/command</param>
		/// <param name="request_Params">remainder of command line once command is removed</param>
		/// <param name="state">current SMTP server state</param>
		public SmtpRequest(SmtpActionType actionType, string request_Params, SmtpState state)
		{
			this.action = actionType;
			this.state = state;
			this.request_Params = request_Params;
		}
Exemple #9
0
		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="code">response code</param>
		/// <param name="message">response message</param>
		/// <param name="next">next state of the SMTP server</param>
		public SmtpResponse(int code, string message, SmtpState next)
		{
			this.code = code;
			this.message = message;
			this.nextState = next;
		}
Exemple #10
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="code">response code</param>
 /// <param name="message">response message</param>
 /// <param name="next">next state of the SMTP server</param>
 public SmtpResponse(int code, string message, SmtpState next)
 {
     Code      = code;
     Message   = message;
     NextState = next;
 }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="stateId">The ID of the state.</param>
 public State(SmtpState stateId)
 {
     StateId     = stateId;
     Transitions = new Dictionary <string, StateTransition>(StringComparer.OrdinalIgnoreCase);
 }
 /// <summary>
 /// Returns the state with the given ID.
 /// </summary>
 /// <param name="stateId">The state ID to return.</param>
 /// <returns>The state with the given id.</returns>
 public State this[SmtpState stateId] => _states[stateId];
Exemple #13
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="code">response code</param>
 /// <param name="message">response message</param>
 /// <param name="next">next state of the SMTP server</param>
 public SmtpResponse(int code, string message, SmtpState next)
 {
     this.code      = code;
     this.message   = message;
     this.nextState = next;
 }
 /// <summary>
 /// Remove the specified command from the state.
 /// </summary>
 /// <param name="state">The SMTP state to remove the command from.</param>
 /// <param name="command">The command to remove from the state.</param>
 void ISmtpStateMachine.RemoveCommand(SmtpState state, string command)
 {
     if (_stateTable[state].Actions.ContainsKey(command))
     {
         _stateTable[state].Actions.Remove(command);
     }
 }
 /// <summary>
 /// Add a state action.
 /// </summary>
 /// <param name="command">The name of the SMTP command.</param>
 /// <param name="tryMake">The function callback to create the command.</param>
 /// <param name="transitionTo">The state to transition to.</param>
 public void Add(string command, TryMakeDelegate tryMake, SmtpState? transitionTo = null)
 {
     Actions.Add(command, Tuple.Create(tryMake, transitionTo ?? StateId));
 }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="stateId">The ID of the state.</param>
 public State(SmtpState stateId)
 {
     StateId = stateId;
     Actions = new Dictionary<string, Tuple<TryMakeDelegate, SmtpState>>(StringComparer.InvariantCultureIgnoreCase);
 }
 /// <summary>
 /// Returns the state with the given ID.
 /// </summary>
 /// <param name="stateId">The state ID to return.</param>
 /// <returns>The state with the given id.</returns>
 public State this[SmtpState stateId]
 {
     get { return _states[stateId]; }
 }
 /// <summary>
 /// Sets the initial state.
 /// </summary>
 /// <param name="stateId">The ID of the initial state.</param>
 public void Initialize(SmtpState stateId)
 {
     _state = _states[stateId];
 }
Exemple #19
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="stateId">The ID of the state.</param>
 public State(SmtpState stateId)
 {
     StateId = stateId;
     Actions = new Dictionary <string, Tuple <TryMakeDelegate, SmtpState> >(StringComparer.OrdinalIgnoreCase);
 }
 /// <summary>
 /// Sets the initial state.
 /// </summary>
 /// <param name="stateId">The ID of the initial state.</param>
 public void Initialize(SmtpState stateId)
 {
     _current = stateId;
 }
Exemple #21
0
 /// <summary>
 /// Create a new SMTP client request.
 /// </summary>
 /// <param name="actionType">type of action/command</param>
 /// <param name="requestParams">remainder of command line once command is removed</param>
 /// <param name="state">current SMTP server state</param>
 public SmtpRequest(SmtpActionType actionType, string requestParams, SmtpState state)
 {
     _action = actionType;
     _state  = state;
     Params  = requestParams;
 }
 /// <summary>
 /// Accept the state and transition to the new state.
 /// </summary>
 /// <param name="context">The session context to use for accepting session based transitions.</param>
 public void Transition(SmtpSessionContext context)
 {
     _current = _transition.Transition(context);
 }
Exemple #23
0
        /// <summary>
        ///  Create an SMTP request object given a line of the input stream from the client and the current internal state.
        ///  </summary>
        /// <param name="s">line of input</param>
        /// <param name="state">current state</param>
        /// <returns>A populated SmtpRequest object</returns>
        public static SmtpRequest CreateRequest(string s, SmtpState state)
        {
            SmtpActionType action         = null;
            string         request_Params = null;

            if (state == SmtpState.DATA_HDR)
            {
                if (s.Equals("."))
                {
                    action = SmtpActionType.DATA_END;
                }
                else if (s.Length < 1)
                {
                    action = SmtpActionType.BLANK_LINE;
                }
                else
                {
                    action         = SmtpActionType.UNRECOG;
                    request_Params = s;
                }
            }
            else if (state == SmtpState.DATA_BODY)
            {
                if (s.Equals("."))
                {
                    action = SmtpActionType.DATA_END;
                }
                else
                {
                    action         = SmtpActionType.UNRECOG;
                    request_Params = s;
                }
            }
            else
            {
                string su = s.ToUpper();
                if (su.StartsWith("EHLO ") || su.StartsWith("HELO"))
                {
                    action         = SmtpActionType.EHLO;
                    request_Params = s.Substring(5);
                }
                else if (su.StartsWith("MAIL FROM:"))
                {
                    action         = SmtpActionType.MAIL;
                    request_Params = s.Substring(10);
                }
                else if (su.StartsWith("RCPT TO:"))
                {
                    action         = SmtpActionType.RCPT;
                    request_Params = s.Substring(8);
                }
                else if (su.StartsWith("DATA"))
                {
                    action = SmtpActionType.DATA;
                }
                else if (su.StartsWith("QUIT"))
                {
                    action = SmtpActionType.QUIT;
                }
                else if (su.StartsWith("RSET"))
                {
                    action = SmtpActionType.RSET;
                }
                else if (su.StartsWith("NOOP"))
                {
                    action = SmtpActionType.NOOP;
                }
                else if (su.StartsWith("EXPN"))
                {
                    action = SmtpActionType.EXPN;
                }
                else if (su.StartsWith("VRFY"))
                {
                    action = SmtpActionType.VRFY;
                }
                else if (su.StartsWith("HELP"))
                {
                    action = SmtpActionType.HELP;
                }
                else
                {
                    action = SmtpActionType.UNRECOG;
                }
            }

            SmtpRequest req = new SmtpRequest(action, request_Params, state);

            return(req);
        }
 /// <summary>
 /// Add a state action.
 /// </summary>
 /// <param name="command">The name of the SMTP command.</param>
 /// <param name="tryMake">The function callback to create the command.</param>
 /// <param name="transition">The state to transition to.</param>
 public void Add(string command, TryMakeDelegate tryMake, SmtpState transition)
 {
     Add(command, tryMake, context => transition);
 }
Exemple #25
0
        private void HandleCompleteLine(ArraySegment <byte> line)
        {
            var isHandled = false;
            var nextState = _state;

            byte[] response = null;

            ArraySegment <byte> cmd = _emptyBuffer;
            var tokens = new ArraySegment <byte>[] { };

            if (_state != SmtpState.WaitingForEndOfData)
            {
                tokens = Bytes.Split(line, Whitespace);
                if (tokens.Length > 0)
                {
                    Bytes.ToUpper(tokens[0]);
                    cmd = tokens[0];
                }
            }

            if (Bytes.IsSame(RSET, cmd))
            {
                isHandled = true;
                if (tokens.Length == 1)
                {
                    ResetMailInfo();
                    response  = ReplyOk;
                    nextState = SmtpState.WaitingForHelo;
                }
                else
                {
                    response = ReplySyntaxErrorRset;
                }
            }
            else if (_state == SmtpState.WaitingForHelo && Bytes.IsSame(EHLO, cmd))
            {
                isHandled = true;
                if (tokens.Length == 2)
                {
                    response  = ReplyEhlo;
                    nextState = SmtpState.WaitingForMailFrom;
                }
                else
                {
                    response = ReplySyntaxErrorEhlo;
                }
            }
            else if (_state == SmtpState.WaitingForHelo && Bytes.IsSame(HELO, cmd))
            {
                isHandled = true;
                if (tokens.Length == 2)
                {
                    response  = ReplyHelo;
                    nextState = SmtpState.WaitingForMailFrom;
                }
                else
                {
                    response = ReplySyntaxErrorHelo;
                }
            }
            else if (_state == SmtpState.WaitingForMailFrom && Bytes.IsSame(MAIL, cmd))
            {
                isHandled = true;

                // extract mail address between < > after :
                bool go = false;
                int  lt = -1, gt = -1;
                for (var i = line.Offset; i < line.Offset + line.Count; i++)
                {
                    byte ch = line.Array[i];
                    if (go)
                    {
                        if (lt == -1 && ch == LessThan)
                        {
                            lt = i;
                        }
                        if (lt != -1 && ch == GreaterThan)
                        {
                            gt = i;
                            break;
                        }
                    }
                    else if (ch == SemiColon)
                    {
                        go = true;
                    }
                }

                if (lt != -1 && gt != -1)
                {
                    // sender found,
                    _sender = Encoding.ASCII.GetString(line.Array, lt + 1, gt - lt - 1).Trim();

                    // check for optional SIZE=nnnnnnn extension after the sender
                    int sizeOffset = Bytes.OffsetOf(MessageSizeExtension, line.Array, gt + 1, line.Count - gt - 1);
                    if (sizeOffset != -1)
                    {
                        int valueBeginOffset = sizeOffset + MessageSizeExtension.Length;
                        int valueEndOffset   = -1;
                        for (var i = valueBeginOffset; i < line.Offset + line.Count; i++)
                        {
                            byte ch    = line.Array[i];
                            byte digit = Bytes.Digits[ch];
                            if (Whitespace.Contains(ch))
                            {
                                break;
                            }
                            else if (digit > 9 || digit < 0)
                            {
                                valueEndOffset = -1;
                                break;
                            }
                            valueEndOffset = i;
                        }

                        if (valueEndOffset >= valueBeginOffset)
                        {
                            int size = 0, scale = 1;
                            for (var i = valueEndOffset; i >= valueBeginOffset && size < MaximumMessageSize; i--, scale *= 10)
                            {
                                size += Bytes.Digits[line.Array[i]] * scale;
                            }

                            if (size > MaximumMessageSize)
                            {
                                response  = ReplyMessageSizeTooBig;
                                nextState = SmtpState.WaitingForRset;
                            }
                            else
                            {
                                _mailContentExpectedSize = size;
                                response  = ReplyOk;
                                nextState = SmtpState.WaitingForRcptTo;
                            }
                        }
                        else
                        {
                            response = ReplySyntaxErrorMail;
                        }
                    }
                    else
                    {
                        // no size extension
                        response  = ReplyOk;
                        nextState = SmtpState.WaitingForRcptTo;
                    }
                }
                else
                {
                    response = ReplySyntaxErrorMail;
                }
            }
            else if ((_state == SmtpState.WaitingForRcptTo || _state == SmtpState.WaitingForAdditionalRcptTo) && Bytes.IsSame(RCPT, cmd))
            {
                // standard deviation: send only to the last given recipient even if not pretending so.
                isHandled = true;

                // extract mail address between < > after :
                bool go = false;
                int  lt = -1, gt = -1;
                for (var i = line.Offset; i < line.Offset + line.Count; i++)
                {
                    byte ch = line.Array[i];
                    if (go)
                    {
                        if (lt == -1 && ch == LessThan)
                        {
                            lt = i;
                        }
                        if (lt != -1 && ch == GreaterThan)
                        {
                            gt = i;
                            break;
                        }
                    }
                    else if (ch == SemiColon)
                    {
                        go = true;
                    }
                }

                if (lt != -1 && gt != -1)
                {
                    var recipient = Encoding.ASCII.GetString(line.Array, lt + 1, gt - lt - 1).Trim().ToLowerInvariant();
                    if (_server.MailDispatcher.IsMailboxActive(recipient))
                    {
                        _lastRecipient = recipient;
                        response       = ReplyOk;
                        nextState      = SmtpState.WaitingForAdditionalRcptTo;
                    }
                    else
                    {
                        response = ReplyNoSuchUserHere;
                    }
                }
                else
                {
                    response = ReplySyntaxErrorRcpt;
                }
            }
            else if (_state == SmtpState.WaitingForAdditionalRcptTo && Bytes.IsSame(DATA, cmd))
            {
                isHandled = true;
                if (tokens.Length == 1)
                {
                    response = ReplyStartMail;
                    if (_mailContent == null)
                    {
                        // presize stream to avoid garbage & extra reallocation if expected size makes sense.
                        // add a bit of slack for size errors
                        var size = (_mailContentExpectedSize > 0 && _mailContentExpectedSize <= MaximumMessageSize) ? _mailContentExpectedSize + 1024 : 4096;
                        _mailContentId = Guid.NewGuid();
                        _mailContent   = new FileStream(IncomingMailDTO.GetContentFileName(_mailContentId), FileMode.CreateNew, FileAccess.Write, FileShare.None, 16384);
                    }
                    nextState = SmtpState.WaitingForEndOfData;
                }
                else
                {
                    response = ReplySyntaxErrorData;
                }
            }
            else if (_state == SmtpState.WaitingForEndOfData)
            {
                isHandled = true;
                if (line.Count == EndOfMail.Length && Bytes.StartsWith(EndOfMail, line))
                {
                    if (_mailContent.Length <= MaximumMessageSize)
                    {
                        response  = ReplyOk;
                        nextState = SmtpState.WaitingForMailFrom;
                        _mailContent.Flush();
                        _server.MailDispatcher.Enqueue(new IncomingMailDTO(DateTime.UtcNow, _lastRecipient, _sender, (int)_mailContent.Length, _mailContentId));
                        _mailContent.Dispose();
                        _mailContent = null;
                    }
                    else
                    {
                        response  = ReplyMessageSizeTooBig;
                        nextState = SmtpState.WaitingForRset;
                    }
                    ResetMailInfo();
                }
                else
                {
                    // accumulate mail body & handle dot unstuffing (while msg size doesn't exceed maximum size, since it will be discarded later anyway).
                    int offset = line.Offset;
                    int count  = line.Count;
                    if (line.Array[offset] == Dot)
                    {
                        offset++;
                        count--;
                    }

                    if (_mailContent != null && _mailContent.Length + count <= MaximumMessageSize)
                    {
                        _mailContent.Write(line.Array, offset, count);
                    }
                }
            }
            else if (Bytes.IsSame(QUIT, cmd))
            {
                isHandled = true;
                if (tokens.Length == 1)
                {
                    ResetMailInfo();
                    response  = ReplyBye;
                    nextState = SmtpState.Disconnect;
                }
                else
                {
                    response = ReplySyntaxErrorQuit;
                }
            }
            else if (Bytes.IsSame(VRFY, cmd) || Bytes.IsSame(EXPN, cmd))
            {
                isHandled = true;
                response  = ReplyCommandNotImplemented;
            }
            else if (Bytes.IsSame(HELP, cmd))
            {
                isHandled = true;
                response  = ReplyHelp;
            }
            else if (Bytes.IsSame(NOOP, cmd))
            {
                isHandled = true;
                response  = ReplyOk;
            }

            if (!isHandled)
            {
                var isKnownCommand = KnownCommands.Any((knownCmd) => Bytes.IsSame(knownCmd, cmd));
                response = isKnownCommand ? ReplyBadSequence : ReplyUnknownCommand;
            }

            _state = nextState;
            if (response != null && response.Length > 0)
            {
                var e = CreateArgs(SendCompleted, response);
                if (!_socket.SendAsync(e))
                {
                    SendCompleted(_socket, e);
                }
            }
        }
Exemple #26
0
 /// <summary>
 /// Returns the state with the given ID.
 /// </summary>
 /// <param name="stateId">The state ID to return.</param>
 /// <returns>The state with the given id.</returns>
 public State this[SmtpState stateId]
 {
     get { return(_states[stateId]); }
 }
Exemple #27
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="stateId">The ID of the state.</param>
 public State(SmtpState stateId)
 {
     StateId = stateId;
     Actions = new Dictionary <string, Tuple <TryMakeDelegate, SmtpState> >(StringComparer.InvariantCultureIgnoreCase);
 }
Exemple #28
0
 /// <summary>
 /// Create a new SMTP client request.
 /// </summary>
 /// <param name="actionType">type of action/command</param>
 /// <param name="request_Params">remainder of command line once command is removed</param>
 /// <param name="state">current SMTP server state</param>
 public SmtpRequest(SmtpActionType actionType, string request_Params, SmtpState state)
 {
     this.action         = actionType;
     this.state          = state;
     this.request_Params = request_Params;
 }
Exemple #29
0
		/// <summary>
		///  Create an SMTP request object given a line of the input stream from the client and the current internal state.
		///  </summary>
		/// <param name="s">line of input</param>
		/// <param name="state">current state</param>
		/// <returns>A populated SmtpRequest object</returns>
		public static SmtpRequest CreateRequest(string s, SmtpState state)
		{
			SmtpActionType action = null;
			string request_Params = null;

			if (state == SmtpState.DATA_HDR)
			{
				if (s.Equals("."))
				{
					action = SmtpActionType.DATA_END;
				}
				else if (s.Length < 1)
				{
					action = SmtpActionType.BLANK_LINE;
				}
				else
				{
					action = SmtpActionType.UNRECOG;
					request_Params = s;
				}
			}
			else if (state == SmtpState.DATA_BODY)
			{
				if (s.Equals("."))
				{
					action = SmtpActionType.DATA_END;
				}
				else
				{
					action = SmtpActionType.UNRECOG;
					request_Params = s;
				}
			}
			else
			{
				string su = s.ToUpper();
				if (su.StartsWith("EHLO ") || su.StartsWith("HELO"))
				{
					action = SmtpActionType.EHLO;
					request_Params = s.Substring(5);
				}
				else if (su.StartsWith("MAIL FROM:"))
				{
					action = SmtpActionType.MAIL;
					request_Params = s.Substring(10);
				}
				else if (su.StartsWith("RCPT TO:"))
				{
					action = SmtpActionType.RCPT;
					request_Params = s.Substring(8);
				}
				else if (su.StartsWith("DATA"))
				{
					action = SmtpActionType.DATA;
				}
				else if (su.StartsWith("QUIT"))
				{
					action = SmtpActionType.QUIT;
				}
				else if (su.StartsWith("RSET"))
				{
					action = SmtpActionType.RSET;
				}
				else if (su.StartsWith("NOOP"))
				{
					action = SmtpActionType.NOOP;
				}
				else if (su.StartsWith("EXPN"))
				{
					action = SmtpActionType.EXPN;
				}
				else if (su.StartsWith("VRFY"))
				{
					action = SmtpActionType.VRFY;
				}
				else if (su.StartsWith("HELP"))
				{
					action = SmtpActionType.HELP;
				}
				else
				{
					action = SmtpActionType.UNRECOG;
				}
			}

			SmtpRequest req = new SmtpRequest(action, request_Params, state);
			return req;
		}