예제 #1
0
        private void Data(SmtpContext context)
        {
            context.WriteLine(MessageStartData);

            var messageData    = context.MessageData;
            var clientEndPoint = (IPEndPoint)context.Socket.RemoteEndPoint;
            var header         = new StringBuilder();

            header.Append(String.Format("Received: from {0} ({0} [{1}])\r\n", context.ClientDomain, clientEndPoint.Address));

            messageData.AddData(header.ToString());

            var line = context.ReadLine();

            while (!line.Equals("."))
            {
                messageData.AddData(line);
                messageData.AddData("\r\n");
                line = context.ReadLine();
            }

            // Spool the message
            _handler(messageData.ParseMessage());
            context.WriteLine(MessageOk);

            // Reset the connection.
            context.Reset();
        }
예제 #2
0
 /// <summary>
 /// Handle the RCPT TO:&lt;address&gt; command.
 /// </summary>
 private void Rcpt(SmtpContext context, string argument)
 {
     if (context.LastCommand == CommandMail || context.LastCommand == CommandRcpt)
     {
         var emailAddress = ParseAddress(argument);
         if (emailAddress != null)
         {
             // Check to make sure we want to accept this message.
             if (_recipientFilter(context, emailAddress))
             {
                 context.MessageData.AddToAddress(emailAddress);
                 context.LastCommand = CommandRcpt;
                 context.WriteLine(MessageOk);
                 _logger.Debug("Connection {0}: RcptTo address: {1} accepted.", context.ConnectionId, emailAddress);
             }
             else
             {
                 context.WriteLine(MessageUnknownUser);
                 _logger.Debug("Connection {0}: RcptTo address: {1} rejected.  Did not pass Address Filter.", context.ConnectionId, emailAddress);
             }
         }
         else
         {
             _logger.Debug("Connection {0}: RcptTo argument: {1} rejected.  Should be from:<*****@*****.**>", context.ConnectionId, argument);
             context.WriteLine(MessageInvalidAddress);
         }
     }
     else
     {
         context.WriteLine(MessageInvalidCommandOrder);
     }
 }
예제 #3
0
 /// <summary>
 /// Reset the connection state.
 /// </summary>
 private static void Rset(SmtpContext context)
 {
     if (context.LastCommand != -1)
     {
         // Dump the message and reset the context.
         context.Reset();
         context.WriteLine(MessageOk);
     }
     else
     {
         context.WriteLine(MessageInvalidCommandOrder);
     }
 }
예제 #4
0
 /// <summary>
 /// Handles the HELO command.
 /// </summary>
 private void Helo(SmtpContext context, string[] inputs)
 {
     if (context.LastCommand == -1)
     {
         if (inputs.Length == 2)
         {
             context.ClientDomain = inputs[1];
             context.LastCommand  = CommandHelo;
             context.WriteLine(HeloResponse);
         }
         else
         {
             context.WriteLine(MessageInvalidArgumentCount);
         }
     }
     else
     {
         context.WriteLine(MessageInvalidCommandOrder);
     }
 }
예제 #5
0
 /// <summary>
 /// Handle the MAIL FROM:&lt;address&gt; command.
 /// </summary>
 private void Mail(SmtpContext context, string argument)
 {
     if (context.LastCommand == CommandHelo)
     {
         var emailAddress = ParseAddress(argument);
         if (emailAddress == null)
         {
             _logger.Debug("Connection {0}: MailFrom argument: {1} rejected.  Should be from:<*****@*****.**>", context.ConnectionId, argument);
             context.WriteLine(MessageInvalidAddress);
             return;
         }
         context.MessageData.FromAddress = emailAddress;
         context.LastCommand             = CommandMail;
         context.WriteLine(MessageOk);
         _logger.Debug("Connection {0}: MailFrom address: {1} accepted.", context.ConnectionId, emailAddress.ToString());
     }
     else
     {
         context.WriteLine(MessageInvalidCommandOrder);
     }
 }
예제 #6
0
        /// <summary>
        /// ProcessConnection handles a connected TCP Client
        /// and performs all necessary interaction with this
        /// client to comply with RFC821.  This method is thread
        /// safe.
        /// </summary>
        public void HandleConnection(Socket socket)
        {
            long currentConnectionId;

            // Really only need to lock on the long, but that is not
            // allowed.  Is there a better way to do this?
            lock (this)
            {
                currentConnectionId = _connectionId++;
            }

            var context = new SmtpContext(currentConnectionId, socket, _logger);

            try
            {
                SendWelcomeMessage(context);
                ProcessCommands(context);
            }
            catch (Exception exception)
            {
                _logger.Error(exception, "Connection {0}: Error: {1}", context.ConnectionId, exception);
            }
        }
예제 #7
0
        /// <summary>
        /// Handles the command input from the client.  This
        /// message returns when the client issues the quit command.
        /// </summary>
        private void ProcessCommands(SmtpContext context)
        {
            while (true)
            {
                try
                {
                    var inputLine = context.ReadLine();
                    if (inputLine == null)
                    {
                        context.Close();
                        return;
                    }

                    _logger.Debug("ProcessCommands Read: " + inputLine);
                    var inputs = inputLine.Split(" ".ToCharArray());

                    switch (inputs[0].ToLower())
                    {
                    case "helo":
                        Helo(context, inputs);
                        break;

                    case "rset":
                        Rset(context);
                        break;

                    case "noop":
                        context.WriteLine(MessageOk);
                        break;

                    case "quit":
                        context.WriteLine(MessageGoodbye);
                        context.Close();
                        return;

                    case "mail":
                        if (inputs[1].ToLower().StartsWith("from"))
                        {
                            Mail(context, inputLine.Substring(inputLine.IndexOf(" ")));
                            break;
                        }
                        context.WriteLine(MessageUnknownCommand);
                        break;

                    case "rcpt":
                        if (inputs[1].ToLower().StartsWith("to"))
                        {
                            Rcpt(context, inputLine.Substring(inputLine.IndexOf(" ")));
                            break;
                        }
                        context.WriteLine(MessageUnknownCommand);
                        break;

                    case "data":
                        Data(context);
                        break;

                    default:
                        context.WriteLine(MessageUnknownCommand);
                        break;
                    }
                }
                catch (Exception exception)
                {
                    _logger.Error(exception, "Connection {0}: Exception occured while processing commands: {1}", context.ConnectionId, exception);
                    context.WriteLine(MessageSystemError);
                }
            }
        }
예제 #8
0
 /// <summary>
 /// Sends the welcome greeting to the client.
 /// </summary>
 private void SendWelcomeMessage(SmtpContext context)
 {
     context.WriteLine(WelcomeMessage);
 }
예제 #9
0
		private void Data(SmtpContext context)
		{
			context.WriteLine(MessageStartData);
			
			var messageData = context.MessageData;
			var clientEndPoint = (IPEndPoint) context.Socket.RemoteEndPoint;
			var header = new StringBuilder();
			header.Append(String.Format("Received: from {0} ({0} [{1}])\r\n", context.ClientDomain, clientEndPoint.Address));
			
			messageData.AddData(header.ToString());
			
			var line = context.ReadLine();
			while(!line.Equals("."))
			{
				messageData.AddData(line);
				messageData.AddData("\r\n");
				line = context.ReadLine();
			}

			// Spool the message
			_handler(messageData.ParseMessage());
			context.WriteLine(MessageOk);
			
			// Reset the connection.
			context.Reset();
		}
예제 #10
0
		/// <summary>
		/// Handle the MAIL FROM:&lt;address&gt; command.
		/// </summary>
		private void Mail(SmtpContext context, string argument)
		{
			if (context.LastCommand == CommandHelo)
			{
				var emailAddress = ParseAddress(argument);
				if (emailAddress == null)
                {
                    _logger.Debug("Connection {0}: MailFrom argument: {1} rejected.  Should be from:<*****@*****.**>", context.ConnectionId, argument);
					context.WriteLine(MessageInvalidAddress);
					return;
				}
				context.MessageData.FromAddress = emailAddress;
				context.LastCommand = CommandMail;
				context.WriteLine(MessageOk);
                _logger.Debug("Connection {0}: MailFrom address: {1} accepted.", context.ConnectionId, emailAddress.ToString());
			}
			else
			{
				context.WriteLine(MessageInvalidCommandOrder);
			}
		}
예제 #11
0
		/// <summary>
		/// Handle the RCPT TO:&lt;address&gt; command.
		/// </summary>
		private void Rcpt(SmtpContext context, string argument)
		{
			if (context.LastCommand == CommandMail || context.LastCommand == CommandRcpt)
			{				
				var emailAddress = ParseAddress(argument);
				if (emailAddress != null)
				{
					// Check to make sure we want to accept this message.
					if (_recipientFilter(context, emailAddress))
					{						
						context.MessageData.AddToAddress(emailAddress);
						context.LastCommand = CommandRcpt;							
						context.WriteLine(MessageOk);
                        _logger.Debug("Connection {0}: RcptTo address: {1} accepted.", context.ConnectionId, emailAddress);
					}
					else
					{
						context.WriteLine(MessageUnknownUser);
                        _logger.Debug("Connection {0}: RcptTo address: {1} rejected.  Did not pass Address Filter.", context.ConnectionId, emailAddress);
					}
				}
				else
				{
                    _logger.Debug("Connection {0}: RcptTo argument: {1} rejected.  Should be from:<*****@*****.**>", context.ConnectionId, argument);
					context.WriteLine(MessageInvalidAddress);
				}
			}
			else
			{
				context.WriteLine(MessageInvalidCommandOrder);
			}
		}
예제 #12
0
		/// <summary>
		/// Reset the connection state.
		/// </summary>
		private static void Rset(SmtpContext context)
		{
			if (context.LastCommand != -1)
			{
				// Dump the message and reset the context.
				context.Reset();
				context.WriteLine(MessageOk);
			}
			else
			{
				context.WriteLine(MessageInvalidCommandOrder);
			}
		}
예제 #13
0
		/// <summary>
		/// Handles the HELO command.
		/// </summary>
		private void Helo(SmtpContext context, string[] inputs)
		{
			if (context.LastCommand == -1)
			{
				if (inputs.Length == 2)
				{
					context.ClientDomain = inputs[1];
					context.LastCommand = CommandHelo;
					context.WriteLine(HeloResponse);				
				}
				else
				{
					context.WriteLine(MessageInvalidArgumentCount);
				}
			}
			else
			{
				context.WriteLine(MessageInvalidCommandOrder);
			}
		}
예제 #14
0
		/// <summary>
		/// Handles the command input from the client.  This
		/// message returns when the client issues the quit command.
		/// </summary>
		private void ProcessCommands(SmtpContext context)
		{
			while(true)
			{
				try
				{
					var inputLine = context.ReadLine();
					if (inputLine == null)
					{
						context.Close();
						return;
					}

                    _logger.Debug("ProcessCommands Read: " + inputLine);
					var inputs = inputLine.Split(" ".ToCharArray());
					
					switch(inputs[0].ToLower())
					{
						case "helo":
							Helo(context, inputs);
							break;
						case "rset":
							Rset(context);
							break;
						case "noop":
							context.WriteLine(MessageOk);
							break;
						case "quit":
							context.WriteLine(MessageGoodbye);
							context.Close();
							return;
						case "mail":
							if (inputs[1].ToLower().StartsWith("from"))
							{
								Mail(context, inputLine.Substring(inputLine.IndexOf(" ")));
								break;
							}
							context.WriteLine(MessageUnknownCommand);
							break;
						case "rcpt":
							if (inputs[1].ToLower().StartsWith("to")) 							
							{
								Rcpt(context, inputLine.Substring(inputLine.IndexOf(" ")));
								break;
							}
							context.WriteLine(MessageUnknownCommand);
							break;
						case "data":
							Data(context);
							break;
						default:
							context.WriteLine(MessageUnknownCommand);
							break;
					}				
				}
				catch(Exception exception)
				{
                    _logger.Error(exception, "Connection {0}: Exception occured while processing commands: {1}", context.ConnectionId, exception);
					context.WriteLine(MessageSystemError);
				}
			}
		}
예제 #15
0
		/// <summary>
		/// Sends the welcome greeting to the client.
		/// </summary>
		private void SendWelcomeMessage(SmtpContext context)
		{
			context.WriteLine(WelcomeMessage);
		}
예제 #16
0
		/// <summary>
		/// ProcessConnection handles a connected TCP Client
		/// and performs all necessary interaction with this
		/// client to comply with RFC821.  This method is thread 
		/// safe.
		/// </summary>
		public void HandleConnection(Socket socket)
		{
			long currentConnectionId;
			// Really only need to lock on the long, but that is not
			// allowed.  Is there a better way to do this?
			lock(this)
			{
				currentConnectionId = _connectionId++;
			}
			
			var context = new SmtpContext(currentConnectionId, socket, _logger);
			
			try 
			{
				SendWelcomeMessage(context);
				ProcessCommands(context);
			}
			catch(Exception exception)
			{
				_logger.Error(exception, "Connection {0}: Error: {1}", context.ConnectionId, exception);
			}
		}