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; } }; }
private bool Route(string file) { bool routed = false; switch (file) { case "/files/index.html": if (!this.User.IsLoggedIn) { this.Redirect("/login/"); routed = true; } break; case "/files/logout.html": Cookie cookieUsername = new Cookie(User.COOKIE_USERNAME, "", "/"); cookieUsername.Expired = true; cookieUsername.Expires = DateTime.Now.Subtract(new TimeSpan(1, 0, 0)); Cookie cookiePassword = new Cookie(User.COOKIE_PASSWORD, "", "/"); cookiePassword.Expired = true; cookiePassword.Expires = DateTime.Now.Subtract(new TimeSpan(1, 0, 0)); this.Response.SetCookie(cookieUsername); this.Response.SetCookie(cookiePassword); this.Redirect("/"); routed = true; break; case "/files/login.html": if (this.Request.HttpMethod == "POST") { using (HttpPostRequest.HttpPostRequest postRequest = new HttpPostRequest.HttpPostRequest(this.Request)) { if (postRequest.Parameters[User.COOKIE_USERNAME] != null && postRequest.Parameters[User.COOKIE_PASSWORD] != null) { User user = new User(); if (user.RefreshByUsernamePassword(postRequest.Parameters[User.COOKIE_USERNAME], postRequest.Parameters[User.COOKIE_PASSWORD])) { this.Response.SetCookie(new Cookie(User.COOKIE_USERNAME, user.Username, "/")); this.Response.SetCookie(new Cookie(User.COOKIE_PASSWORD, user.Password, "/")); this.Redirect("/"); routed = true; } else if (user.RefreshByEMailPassword(postRequest.Parameters[User.COOKIE_USERNAME], postRequest.Parameters[User.COOKIE_PASSWORD])) { this.Response.SetCookie(new Cookie(User.COOKIE_USERNAME, user.Username, "/")); this.Response.SetCookie(new Cookie(User.COOKIE_PASSWORD, user.Password, "/")); this.Redirect("/"); routed = true; } else { if (postRequest.Parameters[User.COOKIE_USERNAME] == this.DefaultAdminUserName && postRequest.Parameters[User.COOKIE_PASSWORD] == this.DefaultAdminUserPassword) { user = new User(postRequest.Parameters[User.COOKIE_USERNAME], postRequest.Parameters[User.COOKIE_PASSWORD], UserAuthorization.Administrator, UserStatus.Active); this.Response.SetCookie(new Cookie(User.COOKIE_USERNAME, user.Username, "/")); this.Response.SetCookie(new Cookie(User.COOKIE_PASSWORD, user.Password, "/")); this.Redirect("/"); routed = true; } } } } } break; case "/files/register.html": if (this.Request.HttpMethod == "POST") { using (HttpPostRequest.HttpPostRequest postRequest = new HttpPostRequest.HttpPostRequest(this.Request)) { if (postRequest.Parameters[User.COOKIE_USERNAME] != null && postRequest.Parameters[User.COOKIE_PASSWORD] != null && postRequest.Parameters["email_address"] != null) { if (!User.NameExists(postRequest.Parameters[User.COOKIE_USERNAME])) { if (!User.EMailExists(postRequest.Parameters["email_address"])) { User newUser = new User(postRequest.Parameters[User.COOKIE_USERNAME], postRequest.Parameters[User.COOKIE_PASSWORD], postRequest.Parameters["email_address"]); newUser.Add(); } } } } } break; } return(routed); }
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; } }; }