Пример #1
0
        private static void Check()
        {
            Console.WriteLine("running precheck...");

            MongoServer mongoServer = MyMongoDB.GetServer();

            MongoDatabase mongoDatabase = mongoServer.GetDatabase("email");
            MongoCollection <LazyBsonDocument> mongoCollection = mongoDatabase.GetCollection <LazyBsonDocument>("mails");

            MongoCursor <LazyBsonDocument> mongoCursor = mongoCollection.FindAll();

            foreach (LazyBsonDocument bsonDocument in mongoCursor)
            {
                if (Options.Verbose)
                {
                    Console.WriteLine("checking email-id: " + bsonDocument["_id"].ToString());
                }
                try {
                    if (User.EMailExists(bsonDocument["RecipientTo"].AsString))
                    {
                        Console.WriteLine("user with email-address found: " + bsonDocument["RecipientTo"].AsString);
                        User newMailUser = new User();
                        newMailUser.RefreshById(User.GetIdByEMail(bsonDocument["RecipientTo"].AsString));
                        eMail mail = new eMail(bsonDocument);
                        mail.AssignToUser(newMailUser);
                    }
                } catch (Exception ex) {
                    logger.ErrorException(ex.Message, ex);
                }
            }

            Console.WriteLine("precheck finished...");
        }
Пример #2
0
        public SmtpServer(TcpClient client, int sslPort) : base(client, sslPort)
        {
            bool   dataStarted = false;
            string mailMessage = String.Empty;

            eMail mail = new eMail();

            this.Connected += (object sender, TcpRequestEventArgs e) => {
                if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null)
                {
                    logger.Debug("connected from remote [{0}:{1}] to local [{2}:{3}]",
                                 e.RemoteEndPoint.Address.ToString(),
                                 e.RemoteEndPoint.Port,
                                 e.LocalEndPoint.Address.ToString(),
                                 e.LocalEndPoint.Port
                                 );
                }

                this.SendMessage("service ready", 220);
            };

            this.Disconnected += (object sender, TcpRequestEventArgs e) => {
                if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null)
                {
                    logger.Debug("disconnected from remote [{0}:{1}] to local [{2}:{3}]",
                                 e.RemoteEndPoint.Address.ToString(),
                                 e.RemoteEndPoint.Port,
                                 e.LocalEndPoint.Address.ToString(),
                                 e.LocalEndPoint.Port
                                 );
                }
            };

            this.LineReceived += (object sender, TcpLineReceivedEventArgs e) => {
                logger.Info(String.Format("[{0}:{1}] to [{2}:{3}] Received Line: \"{4}\"", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, this._localEndPoint.Address.ToString(), this._localEndPoint.Port, e.Line));

                switch (this._state)
                {
                case State.AuthenticateLoginUsername:
                    this._temporaryVariables["username"] = Encoding.UTF8.GetString(Convert.FromBase64String(e.Line)).Trim();
                    if (this._temporaryVariables["username"] != String.Empty)
                    {
                        this._state = State.AuthenticateLoginPassword;

                        if (User.NameExists(this._temporaryVariables["username"]) || User.EMailExists(this._temporaryVariables["username"]))
                        {
                            this.SendMessage(Convert.ToBase64String(Encoding.UTF8.GetBytes("Password:"******"5.7.8 Authentication credentials invalid", 535);
                        }
                    }
                    else
                    {
                        this._temporaryVariables.Remove("username");
                        this._state = State.Default;
                        this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                    }
                    break;

                case State.AuthenticateLoginPassword:
                    this._temporaryVariables["password"] = Encoding.UTF8.GetString(Convert.FromBase64String(e.Line)).Trim();
                    this._state = State.Default;
                    if (this._temporaryVariables["password"] != String.Empty)
                    {
                        string username = this._temporaryVariables["username"];
                        string password = this._temporaryVariables["password"];
                        this._temporaryVariables.Remove("username");
                        this._temporaryVariables.Remove("password");

                        if (this._user.RefreshByUsernamePassword(username, password) || this._user.RefreshByEMailPassword(username, password))
                        {
                            this.SendMessage("2.7.0 Authentication Succeeded", 235);
                        }
                        else
                        {
                            this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                        }
                    }
                    else
                    {
                        this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                    }
                    break;

                case State.AuthenticateCramMD5:
                    List <string> wordsCramMD5 = this.GetWordsFromBase64EncodedLine(e.Line);

                    this._state = State.Default;
                    if (wordsCramMD5.Count == 1)
                    {
                        string[] splittedWords = wordsCramMD5[0].Split(new char[] { ' ' });
                        if (splittedWords.Length == 2)
                        {
                            bool nameExists  = User.NameExists(splittedWords[0]);
                            bool eMailExists = User.EMailExists(splittedWords[0]);
                            if (nameExists || eMailExists)
                            {
                                string userId  = (nameExists) ? User.GetIdByName(splittedWords[0]) : User.GetIdByEMail(splittedWords[0]);
                                User   tmpUser = new User();
                                if (tmpUser.RefreshById(userId))
                                {
                                    string calculatedDigest = this.CalculateCramMD5Digest(tmpUser.Password, this._currentCramMD5Challenge);
                                    if (calculatedDigest == splittedWords[1])
                                    {
                                        this._user = tmpUser;
                                        this.SendMessage("2.7.0 Authentication Succeeded", 235);
                                    }
                                    else
                                    {
                                        this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                                    }
                                }
                                else
                                {
                                    this.SendMessage("4.7.0 Temporary authentication failure", 454);
                                }
                            }
                            else
                            {
                                this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                            }
                        }
                        else
                        {
                            this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                        }
                    }
                    else
                    {
                        this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                    }

                    this._currentCramMD5Challenge = String.Empty;
                    break;

                case State.Default:
                default:
                    if (!dataStarted)
                    {
                        if (e.Line.StartsWith("HELO "))
                        {
                            mail.SetClientName(e.Line.Substring(5));
                            this.SendMessage("OK", 250);
                        }
                        else if (e.Line.StartsWith("EHLO "))
                        {
                            mail.SetClientName(e.Line.Substring(5));
                            this.SendMessage("Hello " + mail.ClientName + " [" + this._remoteEndPoint.Address.ToString() + "]", "250-localhost");
                            if (!this.SslIsActive)
                            {
                                string capabilities = "LOGIN";
                                capabilities += " PLAIN CRAM-MD5";
                                this.SendMessage(capabilities, "250-AUTH");
                                this.SendMessage("STARTTLS", 250);
                            }
                            else
                            {
                                string capabilities = "AUTH LOGIN";
                                capabilities += " PLAIN CRAM-MD5";
                                this.SendMessage(capabilities, 250);
                            }
                        }
                        else if (e.Line.StartsWith("AUTH "))
                        {
                            Match authMatch = Regex.Match(e.Line, @"^AUTH\s+(PLAIN|CRAM-MD5|LOGIN)(.*)?", RegexOptions.IgnoreCase);
                            if (authMatch.Success)
                            {
                                switch (authMatch.Groups[1].Value.ToUpper())
                                {
                                case "PLAIN":
                                    List <string> words = new List <string>();
                                    try {
                                        words = this.GetWordsFromBase64EncodedLine(authMatch.Groups[2].Value);
                                    } catch (Exception) {
                                    }

                                    this._state = State.Default;
                                    if (words.Count == 2)
                                    {
                                        if (words[0] != String.Empty && words[1] != String.Empty)
                                        {
                                            if (this._user.RefreshByUsernamePassword(words[0], words[1]) || this._user.RefreshByEMailPassword(words[0], words[1]))
                                            {
                                                this.SendMessage("2.7.0 Authentication Succeeded", 235);
                                            }
                                            else
                                            {
                                                this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                                            }
                                        }
                                        else
                                        {
                                            this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                                        }
                                    }
                                    else
                                    {
                                        this.SendMessage("5.7.8 Authentication credentials invalid", 535);
                                    }
                                    break;

                                case "LOGIN":
                                    this._state = State.AuthenticateLoginUsername;
                                    this.SendMessage(Convert.ToBase64String(Encoding.UTF8.GetBytes("Username:"******"CRAM-MD5":
                                    this._state = State.AuthenticateCramMD5;
                                    string base64EncodedCramMD5Challenge = this.CalculateOneTimeBase64Challenge("localhost.de");
                                    this._currentCramMD5Challenge = Encoding.UTF8.GetString(Convert.FromBase64String(base64EncodedCramMD5Challenge));
                                    this.SendMessage(base64EncodedCramMD5Challenge, 334);
                                    break;

                                default:
                                    this.SendMessage("Unrecognized authentication type", 504);
                                    break;
                                }
                            }
                        }
                        else if (e.Line.StartsWith("MAIL FROM:"))
                        {
                            string email = e.Line.Substring(10);
                            try {
                                mail.SetFrom(email);
                                this.SendMessage("OK", 250);
                            } catch (FormatException) {
                                this.SendMessage("BAD <" + email + ">... Denied due to invalid email-format", 555);
                            }
                        }
                        else if (e.Line.StartsWith("RCPT TO:"))
                        {
                            mail.SetRecipient(e.Line.Substring(8));
                            this.SendMessage("OK", 250);
                        }
                        else if (e.Line.StartsWith("STARTTLS"))
                        {
                            if (e.Line.Trim() == "STARTTLS")
                            {
                                this.SendMessage("Ready to start TLS", 220);
                                if (!this.StartTls())
                                {
                                    this.SendMessage("TLS not available due to temporary reason", 454);
                                }
                            }
                            else
                            {
                                this.SendMessage("Syntax error (no parameters allowed)", 501);
                            }
                        }
                        else if (e.Line == "DATA")
                        {
                            this.SendMessage("start mail input", 354);
                            dataStarted = true;
                        }
                        else if (e.Line == "QUIT")
                        {
                            if (eMailServer.Options.Verbose)
                            {
                                logger.Debug("[{0}:{1}] to [{2}:{3}] quit connection", this._localEndPoint.Address.ToString(), this._localEndPoint.Port, this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port);
                            }
                            this.Close();
                            return;
                        }
                        else
                        {
                            this.SendMessage("Syntax error, command unrecognized", 500);
                            if (eMailServer.Options.Verbose)
                            {
                                logger.Debug("[{0}:{1}] to [{2}:{3}] unknown command: {2}", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, this._localEndPoint.Address.ToString(), this._localEndPoint.Port, e.Line);
                            }
                        }
                    }
                    else
                    {
                        if (e.Line == ".")
                        {
                            mailMessage = mailMessage.Trim();
                            logger.Info("[{0}:{1}] to [{2}:{3}] eMail data received: {2}", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, mailMessage, this._localEndPoint.Address.ToString(), this._localEndPoint.Port);
                            dataStarted = false;

                            mail.ParseData(mailMessage);
                            if (mail.IsValid)
                            {
                                if (this._user.IsLoggedIn && User.EMailExists(mail.MailFrom))
                                {
                                    mail.SetUser(this._user);
                                    mail.SetFolder("SENT");
                                }
                                else
                                {
                                    mail.SetFolder("INBOX");
                                }

                                mail.SaveToMongoDB();
                            }
                            else
                            {
                                logger.Error("received message is invalid for saving to database.");
                            }

                            this.SendMessage("OK", 250);
                        }
                        else
                        {
                            mailMessage += e.Line + "\r\n";
                        }
                    }
                    break;
                }
            };
        }
Пример #3
0
		public ImapServer(TcpClient client, int imapSslPort) : base(client, imapSslPort) {
			this.Connected += (object sender, TcpRequestEventArgs e) => {
				if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null) {
					logger.Debug("connected from remote [{0}:{1}] to local [{2}:{3}]",
						e.RemoteEndPoint.Address.ToString(),
					    e.RemoteEndPoint.Port,
					    e.LocalEndPoint.Address.ToString(),
					    e.LocalEndPoint.Port
					);
				}
				
				this.SendMessage("OK IMAP4rev1 Service Ready", "*");
			};
			
			this.Disconnected += (object sender, TcpRequestEventArgs e) => {
				if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null) {
					logger.Debug("disconnected from remote [{0}:{1}] to local [{2}:{3}]",
						e.RemoteEndPoint.Address.ToString(),
					    e.RemoteEndPoint.Port,
					    e.LocalEndPoint.Address.ToString(),
					    e.LocalEndPoint.Port
					);
				}
			};
			
			this.LineReceived += (object sender, TcpLineReceivedEventArgs e) => {
				logger.Info(String.Format("[{0}:{1}] to [{2}:{3}] Received Line: \"{4}\"", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, this._localEndPoint.Address.ToString(), this._localEndPoint.Port, e.Line));
				
				switch(this._state) {
					case State.AuthenticateCramMD5:
						List<string> wordsCramMD5 = this.GetWordsFromBase64EncodedLine(e.Line);
						
						this._state = State.Default;
						if (wordsCramMD5.Count == 1) {
							string[] splittedWords = wordsCramMD5[0].Split(new char[] {' '});
							if (splittedWords.Length == 2) {
								bool nameExists = User.NameExists(splittedWords[0]);
								bool eMailExists = User.EMailExists(splittedWords[0]);
								if (nameExists || eMailExists) {
									string userId = (nameExists) ? User.GetIdByName(splittedWords[0]) : User.GetIdByEMail(splittedWords[0]);
									User tmpUser = new User();
									if (tmpUser.RefreshById(userId)) {
										string calculatedDigest = this.CalculateCramMD5Digest(tmpUser.Password, this._currentCramMD5Challenge);
										if (calculatedDigest == splittedWords[1]) {
											this._user = tmpUser;
											this.SendMessage("OK PLAIN AUTHENTICATION successful", this._lastClientId);
										} else {
											this.SendMessage("NO invalid authentication", this._lastClientId);
										}
									} else {
										this.SendMessage("NO invalid authentication", this._lastClientId);
									}
								} else {
									this.SendMessage("NO invalid authentication", this._lastClientId);
								}
							} else {
								this.SendMessage("NO invalid authentication", this._lastClientId);
							}
						} else {
							this.SendMessage("NO invalid authentication", this._lastClientId);
						}
						
						this._currentCramMD5Challenge = String.Empty;
						break;
						
					case State.AuthenticatePlain:
						List<string> words = new List<string>();
						try {
							words = this.GetWordsFromBase64EncodedLine(e.Line);
						} catch(Exception) {
							// maybe it is not base64-encoded
							Match plainTextMatch = Regex.Match(e.Line, "\\s+LOGIN\\s+\"([^\"]+)\"\\s+\"([^\"]+)\"", RegexOptions.IgnoreCase);
							if (plainTextMatch.Success) {
								words.Add(plainTextMatch.Groups[1].Value);
								words.Add(plainTextMatch.Groups[2].Value);
							}
						}
						
						this._state = State.Default;
						if (words.Count == 2) {
							if (words[0] != String.Empty && words[1] != String.Empty) {
								if (this._user.RefreshByUsernamePassword(words[0], words[1]) || this._user.RefreshByEMailPassword(words[0], words[1])) {
									this.SendMessage("OK PLAIN AUTHENTICATION successful", this._lastClientId);
								} else {
									this.SendMessage("NO invalid authentication", this._lastClientId);
								}
							} else {
								this.SendMessage("NO invalid authentication", this._lastClientId);
							}
						} else {
							this.SendMessage("NO invalid authentication", this._lastClientId);
						}
						break;
					
					case State.Default:
						Match clientCommandMatch = Regex.Match(e.Line, @"^([^\s]+)\s+(\w+)(\s.+)?", RegexOptions.IgnoreCase);
						if (clientCommandMatch.Success) {
							this._lastClientId = clientCommandMatch.Groups[1].Value;
		
							switch(clientCommandMatch.Groups[2].Value.ToUpper()) {
								case "AUTHENTICATE":
									this.Authenticate(clientCommandMatch.Groups[3].Value.Trim().ToUpper());
									break;
		
								case "CAPABILITY":
									string capabilities = "CAPABILITY IMAP4rev1 LOGIN";
									if (!this.SslIsActive) {
										capabilities += " STARTTLS";
									}
									capabilities += " AUTH=PLAIN";
									capabilities += " AUTH=CRAM-MD5";
									this.SendMessage(capabilities, "*");
									this.SendMessage("OK CAPABILITY completed", this._lastClientId);
									break;
								
								case "CHECK":
									this.SendMessage("OK CHECK completed", this._lastClientId);
									break;
									
								case "FETCH":
									this.Fetch();
									break;
								
								case "LOGOUT":
									this.Logout((TcpRequestHandler.TcpRequestHandler)sender);
									break;
									
								case "NOOP":
									this.SendMessage("OK NOOP completed", this._lastClientId);
									break;
									
								case "SELECT":
									this.Select(clientCommandMatch.Groups[3].Value.ToUpper());
									break;

								case "LSUB":
									Match lsubMatch = Regex.Match(clientCommandMatch.Groups[3].Value, "\"([^\"]*)\"\\s+\"([^\"]*)\"", RegexOptions.Compiled);
									if (lsubMatch.Success) {
										List<string> folders = this._user.GetFolders(lsubMatch.Groups[1].Value, lsubMatch.Groups[2].Value);
										foreach(string folder in folders) {
											this.SendMessage("LSUB () \"/\" \"" + folder + "\"", "*");
										}
									}
									this.SendMessage("OK LSUB completed", this._lastClientId);
									break;
								
								case "LIST":
									this.List(clientCommandMatch.Groups[3].Value.ToUpper());
									break;
								
								case "STARTTLS":
									this.SendMessage("OK Begin TLS negotiation now", this._lastClientId);
									if (this.StartTls()) {
										this.SendMessage("OK STARTTLS completed", this._lastClientId);
									} else {
										this.SendMessage("NO STARTTLS not supported", this._lastClientId);
									}
									break;
								
								case "UID":
									this.Uid(clientCommandMatch.Groups[3].Value.Trim());
									break;
								
								default:
									this.SendMessage("BAD " + clientCommandMatch.Groups[2].Value + " command not found", this._lastClientId);
									break;
							}
						} else {
							this.SendMessage("BAD invalid command line: " + e.Line, this._lastClientId);
						}
						break;
				}
			};
		}
Пример #4
0
        public ImapServer(TcpClient client, int imapSslPort) : base(client, imapSslPort)
        {
            this.Connected += (object sender, TcpRequestEventArgs e) => {
                if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null)
                {
                    logger.Debug("connected from remote [{0}:{1}] to local [{2}:{3}]",
                                 e.RemoteEndPoint.Address.ToString(),
                                 e.RemoteEndPoint.Port,
                                 e.LocalEndPoint.Address.ToString(),
                                 e.LocalEndPoint.Port
                                 );
                }

                this.SendMessage("OK IMAP4rev1 Service Ready", "*");
            };

            this.Disconnected += (object sender, TcpRequestEventArgs e) => {
                if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null)
                {
                    logger.Debug("disconnected from remote [{0}:{1}] to local [{2}:{3}]",
                                 e.RemoteEndPoint.Address.ToString(),
                                 e.RemoteEndPoint.Port,
                                 e.LocalEndPoint.Address.ToString(),
                                 e.LocalEndPoint.Port
                                 );
                }
            };

            this.LineReceived += (object sender, TcpLineReceivedEventArgs e) => {
                logger.Info(String.Format("[{0}:{1}] to [{2}:{3}] Received Line: \"{4}\"", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, this._localEndPoint.Address.ToString(), this._localEndPoint.Port, e.Line));

                switch (this._state)
                {
                case State.AuthenticateCramMD5:
                    List <string> wordsCramMD5 = this.GetWordsFromBase64EncodedLine(e.Line);

                    this._state = State.Default;
                    if (wordsCramMD5.Count == 1)
                    {
                        string[] splittedWords = wordsCramMD5[0].Split(new char[] { ' ' });
                        if (splittedWords.Length == 2)
                        {
                            bool nameExists  = User.NameExists(splittedWords[0]);
                            bool eMailExists = User.EMailExists(splittedWords[0]);
                            if (nameExists || eMailExists)
                            {
                                string userId  = (nameExists) ? User.GetIdByName(splittedWords[0]) : User.GetIdByEMail(splittedWords[0]);
                                User   tmpUser = new User();
                                if (tmpUser.RefreshById(userId))
                                {
                                    string calculatedDigest = this.CalculateCramMD5Digest(tmpUser.Password, this._currentCramMD5Challenge);
                                    if (calculatedDigest == splittedWords[1])
                                    {
                                        this._user = tmpUser;
                                        this.SendMessage("OK PLAIN AUTHENTICATION successful", this._lastClientId);
                                    }
                                    else
                                    {
                                        this.SendMessage("NO invalid authentication", this._lastClientId);
                                    }
                                }
                                else
                                {
                                    this.SendMessage("NO invalid authentication", this._lastClientId);
                                }
                            }
                            else
                            {
                                this.SendMessage("NO invalid authentication", this._lastClientId);
                            }
                        }
                        else
                        {
                            this.SendMessage("NO invalid authentication", this._lastClientId);
                        }
                    }
                    else
                    {
                        this.SendMessage("NO invalid authentication", this._lastClientId);
                    }

                    this._currentCramMD5Challenge = String.Empty;
                    break;

                case State.AuthenticatePlain:
                    List <string> words = new List <string>();
                    try {
                        words = this.GetWordsFromBase64EncodedLine(e.Line);
                    } catch (Exception) {
                        // maybe it is not base64-encoded
                        Match plainTextMatch = Regex.Match(e.Line, "\\s+LOGIN\\s+\"([^\"]+)\"\\s+\"([^\"]+)\"", RegexOptions.IgnoreCase);
                        if (plainTextMatch.Success)
                        {
                            words.Add(plainTextMatch.Groups[1].Value);
                            words.Add(plainTextMatch.Groups[2].Value);
                        }
                    }

                    this._state = State.Default;
                    if (words.Count == 2)
                    {
                        if (words[0] != String.Empty && words[1] != String.Empty)
                        {
                            if (this._user.RefreshByUsernamePassword(words[0], words[1]) || this._user.RefreshByEMailPassword(words[0], words[1]))
                            {
                                this.SendMessage("OK PLAIN AUTHENTICATION successful", this._lastClientId);
                            }
                            else
                            {
                                this.SendMessage("NO invalid authentication", this._lastClientId);
                            }
                        }
                        else
                        {
                            this.SendMessage("NO invalid authentication", this._lastClientId);
                        }
                    }
                    else
                    {
                        this.SendMessage("NO invalid authentication", this._lastClientId);
                    }
                    break;

                case State.Default:
                    Match clientCommandMatch = Regex.Match(e.Line, @"^([^\s]+)\s+(\w+)(\s.+)?", RegexOptions.IgnoreCase);
                    if (clientCommandMatch.Success)
                    {
                        this._lastClientId = clientCommandMatch.Groups[1].Value;

                        switch (clientCommandMatch.Groups[2].Value.ToUpper())
                        {
                        case "AUTHENTICATE":
                            this.Authenticate(clientCommandMatch.Groups[3].Value.Trim().ToUpper());
                            break;

                        case "CAPABILITY":
                            string capabilities = "CAPABILITY IMAP4rev1 LOGIN";
                            if (!this.SslIsActive)
                            {
                                capabilities += " STARTTLS";
                            }
                            capabilities += " AUTH=PLAIN";
                            capabilities += " AUTH=CRAM-MD5";
                            this.SendMessage(capabilities, "*");
                            this.SendMessage("OK CAPABILITY completed", this._lastClientId);
                            break;

                        case "CHECK":
                            this.SendMessage("OK CHECK completed", this._lastClientId);
                            break;

                        case "FETCH":
                            this.Fetch();
                            break;

                        case "LOGOUT":
                            this.Logout((TcpRequestHandler.TcpRequestHandler)sender);
                            break;

                        case "NOOP":
                            this.SendMessage("OK NOOP completed", this._lastClientId);
                            break;

                        case "SELECT":
                            this.Select(clientCommandMatch.Groups[3].Value.ToUpper());
                            break;

                        case "LSUB":
                            Match lsubMatch = Regex.Match(clientCommandMatch.Groups[3].Value, "\"([^\"]*)\"\\s+\"([^\"]*)\"", RegexOptions.Compiled);
                            if (lsubMatch.Success)
                            {
                                List <string> folders = this._user.GetFolders(lsubMatch.Groups[1].Value, lsubMatch.Groups[2].Value);
                                foreach (string folder in folders)
                                {
                                    this.SendMessage("LSUB () \"/\" \"" + folder + "\"", "*");
                                }
                            }
                            this.SendMessage("OK LSUB completed", this._lastClientId);
                            break;

                        case "LIST":
                            this.List(clientCommandMatch.Groups[3].Value.ToUpper());
                            break;

                        case "STARTTLS":
                            this.SendMessage("OK Begin TLS negotiation now", this._lastClientId);
                            if (this.StartTls())
                            {
                                this.SendMessage("OK STARTTLS completed", this._lastClientId);
                            }
                            else
                            {
                                this.SendMessage("NO STARTTLS not supported", this._lastClientId);
                            }
                            break;

                        case "UID":
                            this.Uid(clientCommandMatch.Groups[3].Value.Trim());
                            break;

                        default:
                            this.SendMessage("BAD " + clientCommandMatch.Groups[2].Value + " command not found", this._lastClientId);
                            break;
                        }
                    }
                    else
                    {
                        this.SendMessage("BAD invalid command line: " + e.Line, this._lastClientId);
                    }
                    break;
                }
            };
        }
Пример #5
0
		public SmtpServer(TcpClient client, int sslPort) : base(client, sslPort) {
			bool dataStarted = false;
			string mailMessage = String.Empty;

			eMail mail = new eMail();

			this.Connected += (object sender, TcpRequestEventArgs e) => {
				if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null) {
					logger.Debug("connected from remote [{0}:{1}] to local [{2}:{3}]",
						e.RemoteEndPoint.Address.ToString(),
					    e.RemoteEndPoint.Port,
					    e.LocalEndPoint.Address.ToString(),
					    e.LocalEndPoint.Port
					);
				}

				this.SendMessage("service ready", 220);
			};
			
			this.Disconnected += (object sender, TcpRequestEventArgs e) => {
				if (this.Verbose && e.RemoteEndPoint != null && e.LocalEndPoint != null) {
					logger.Debug("disconnected from remote [{0}:{1}] to local [{2}:{3}]",
						e.RemoteEndPoint.Address.ToString(),
					    e.RemoteEndPoint.Port,
					    e.LocalEndPoint.Address.ToString(),
					    e.LocalEndPoint.Port
					);
				}
			};

			this.LineReceived += (object sender, TcpLineReceivedEventArgs e) => {
				logger.Info(String.Format("[{0}:{1}] to [{2}:{3}] Received Line: \"{4}\"", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, this._localEndPoint.Address.ToString(), this._localEndPoint.Port, e.Line));

				switch(this._state) {
					case State.AuthenticateLoginUsername:
						this._temporaryVariables["username"] = Encoding.UTF8.GetString(Convert.FromBase64String(e.Line)).Trim();
						if (this._temporaryVariables["username"] != String.Empty) {
							this._state = State.AuthenticateLoginPassword;

							if (User.NameExists(this._temporaryVariables["username"]) || User.EMailExists(this._temporaryVariables["username"])) {
								this.SendMessage(Convert.ToBase64String(Encoding.UTF8.GetBytes("Password:"******"5.7.8 Authentication credentials invalid", 535);
							}
						} else {
							this._temporaryVariables.Remove("username");
							this._state = State.Default;
							this.SendMessage("5.7.8 Authentication credentials invalid", 535);
						}
						break;
					
					case State.AuthenticateLoginPassword:
						this._temporaryVariables["password"] = Encoding.UTF8.GetString(Convert.FromBase64String(e.Line)).Trim();
						this._state = State.Default;
						if (this._temporaryVariables["password"] != String.Empty) {
							string username = this._temporaryVariables["username"];
							string password = this._temporaryVariables["password"];
							this._temporaryVariables.Remove("username");
							this._temporaryVariables.Remove("password");

							if (this._user.RefreshByUsernamePassword(username, password) || this._user.RefreshByEMailPassword(username, password)) {
								this.SendMessage("2.7.0 Authentication Succeeded", 235);
							} else {
								this.SendMessage("5.7.8 Authentication credentials invalid", 535);
							}
						} else {
							this.SendMessage("5.7.8 Authentication credentials invalid", 535);
						}
						break;
					
					case State.AuthenticateCramMD5:
						List<string> wordsCramMD5 = this.GetWordsFromBase64EncodedLine(e.Line);
						
						this._state = State.Default;
						if (wordsCramMD5.Count == 1) {
							string[] splittedWords = wordsCramMD5[0].Split(new char[] {' '});
							if (splittedWords.Length == 2) {
								bool nameExists = User.NameExists(splittedWords[0]);
								bool eMailExists = User.EMailExists(splittedWords[0]);
								if (nameExists || eMailExists) {
									string userId = (nameExists) ? User.GetIdByName(splittedWords[0]) : User.GetIdByEMail(splittedWords[0]);
									User tmpUser = new User();
									if (tmpUser.RefreshById(userId)) {
										string calculatedDigest = this.CalculateCramMD5Digest(tmpUser.Password, this._currentCramMD5Challenge);
										if (calculatedDigest == splittedWords[1]) {
											this._user = tmpUser;
											this.SendMessage("2.7.0 Authentication Succeeded", 235);
										} else {
											this.SendMessage("5.7.8 Authentication credentials invalid", 535);
										}
									} else {
										this.SendMessage("4.7.0 Temporary authentication failure", 454);
									}
								} else {
									this.SendMessage("5.7.8 Authentication credentials invalid", 535);
								}
							} else {
								this.SendMessage("5.7.8 Authentication credentials invalid", 535);
							}
						} else {
							this.SendMessage("5.7.8 Authentication credentials invalid", 535);
						}
						
						this._currentCramMD5Challenge = String.Empty;
						break;

					case State.Default:
					default:
						if (!dataStarted) {
							if (e.Line.StartsWith("HELO ")) {
								mail.SetClientName(e.Line.Substring(5));
								this.SendMessage("OK", 250);
							} else if (e.Line.StartsWith("EHLO ")) {
								mail.SetClientName(e.Line.Substring(5));
								this.SendMessage("Hello " + mail.ClientName + " [" + this._remoteEndPoint.Address.ToString() + "]", "250-localhost");
								if (!this.SslIsActive) {
									string capabilities = "LOGIN";
									capabilities += " PLAIN CRAM-MD5";
									this.SendMessage(capabilities, "250-AUTH");
									this.SendMessage("STARTTLS", 250);
								} else {
									string capabilities = "AUTH LOGIN";
									capabilities += " PLAIN CRAM-MD5";
									this.SendMessage(capabilities, 250);
								}
							} else if (e.Line.StartsWith("AUTH ")) {
								Match authMatch = Regex.Match(e.Line, @"^AUTH\s+(PLAIN|CRAM-MD5|LOGIN)(.*)?", RegexOptions.IgnoreCase);
								if (authMatch.Success) {
									switch(authMatch.Groups[1].Value.ToUpper()) {
										case "PLAIN":
											List<string> words = new List<string>();
											try {
												words = this.GetWordsFromBase64EncodedLine(authMatch.Groups[2].Value);
											} catch(Exception) {

											}
						
											this._state = State.Default;
											if (words.Count == 2) {
												if (words[0] != String.Empty && words[1] != String.Empty) {
													if (this._user.RefreshByUsernamePassword(words[0], words[1]) || this._user.RefreshByEMailPassword(words[0], words[1])) {
														this.SendMessage("2.7.0 Authentication Succeeded", 235);
													} else {
														this.SendMessage("5.7.8 Authentication credentials invalid", 535);
													}
												} else {
													this.SendMessage("5.7.8 Authentication credentials invalid", 535);
												}
											} else {
												this.SendMessage("5.7.8 Authentication credentials invalid", 535);
											}
											break;
										
										case "LOGIN":
											this._state = State.AuthenticateLoginUsername;
											this.SendMessage(Convert.ToBase64String(Encoding.UTF8.GetBytes("Username:"******"CRAM-MD5":
											this._state = State.AuthenticateCramMD5;
											string base64EncodedCramMD5Challenge = this.CalculateOneTimeBase64Challenge("localhost.de");
											this._currentCramMD5Challenge = Encoding.UTF8.GetString(Convert.FromBase64String(base64EncodedCramMD5Challenge));
											this.SendMessage(base64EncodedCramMD5Challenge, 334);
											break;

										default:
											this.SendMessage("Unrecognized authentication type", 504);
											break;
									}
								}
							} else if (e.Line.StartsWith("MAIL FROM:")) {
								string email = e.Line.Substring(10);
								try {
									mail.SetFrom(email);
									this.SendMessage("OK", 250);
								} catch(FormatException) {
									this.SendMessage("BAD <" + email + ">... Denied due to invalid email-format", 555);
								}
							} else if (e.Line.StartsWith("RCPT TO:")) {
								mail.SetRecipient(e.Line.Substring(8));
								this.SendMessage("OK", 250);
							} else if (e.Line.StartsWith("STARTTLS")) {
								if (e.Line.Trim() == "STARTTLS") {
									this.SendMessage("Ready to start TLS", 220);
									if (!this.StartTls()) {
										this.SendMessage("TLS not available due to temporary reason", 454);
									}
								} else {
									this.SendMessage("Syntax error (no parameters allowed)", 501);
								}
							} else if (e.Line == "DATA") {
								this.SendMessage("start mail input", 354);
								dataStarted = true;
							} else if (e.Line == "QUIT") {
								if (eMailServer.Options.Verbose) {
									logger.Debug("[{0}:{1}] to [{2}:{3}] quit connection", this._localEndPoint.Address.ToString(), this._localEndPoint.Port, this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port);
								}
								this.Close();
								return;
							} else {
								this.SendMessage("Syntax error, command unrecognized", 500);
								if (eMailServer.Options.Verbose) {
									logger.Debug("[{0}:{1}] to [{2}:{3}] unknown command: {2}", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, this._localEndPoint.Address.ToString(), this._localEndPoint.Port, e.Line);
								}
							}
						} else {
							if (e.Line == ".") {
								mailMessage = mailMessage.Trim();
								logger.Info("[{0}:{1}] to [{2}:{3}] eMail data received: {2}", this._remoteEndPoint.Address.ToString(), this._remoteEndPoint.Port, mailMessage, this._localEndPoint.Address.ToString(), this._localEndPoint.Port);
								dataStarted = false;

								mail.ParseData(mailMessage);
								if (mail.IsValid) {
									if (this._user.IsLoggedIn && User.EMailExists(mail.MailFrom)) {
										mail.SetUser(this._user);
										mail.SetFolder("SENT");
									} else {
										mail.SetFolder("INBOX");
									}

									mail.SaveToMongoDB();
								} else {
									logger.Error("received message is invalid for saving to database.");
								}

								this.SendMessage("OK", 250);
							} else {
								mailMessage += e.Line + "\r\n";
							}
						}
						break;
				}
			};
		}
Пример #6
0
		private static void Check() {
			Console.WriteLine("running precheck...");
			
			MongoServer mongoServer = MyMongoDB.GetServer();
			
			MongoDatabase mongoDatabase = mongoServer.GetDatabase("email");
			MongoCollection<LazyBsonDocument> mongoCollection = mongoDatabase.GetCollection<LazyBsonDocument>("mails");
			
			MongoCursor<LazyBsonDocument> mongoCursor = mongoCollection.FindAll();
			foreach(LazyBsonDocument bsonDocument in mongoCursor) {
				if (Options.Verbose) {
					Console.WriteLine("checking email-id: " + bsonDocument["_id"].ToString());
				}
				try {
					if (User.EMailExists(bsonDocument["RecipientTo"].AsString)) {
						Console.WriteLine("user with email-address found: " + bsonDocument["RecipientTo"].AsString);
						User newMailUser = new User();
						newMailUser.RefreshById(User.GetIdByEMail(bsonDocument["RecipientTo"].AsString));
						eMail mail = new eMail(bsonDocument);
						mail.AssignToUser(newMailUser);
					}
				} catch(Exception ex) {
					logger.ErrorException(ex.Message, ex);
				}
			}
			
			Console.WriteLine("precheck finished...");
		}