using SMTPServer; using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; using System.Linq; namespace MailServer.SMTPServer { class SmtpServerSession : SmtpSession { private bool Initialized { get; set; } private string SenderHostname { get; set; } private bool MailFromSet { get; set; } private string MailFrom { get; set; } private List Recipients { get; set; } private bool WaitForData { get; set; } private string Data { get; set; } private bool FreeLine { get; set; } private bool AuthActive { get; set; } private string Username { get; set; } private string Password { get; set; } private bool Authenticated { get; set; } public SmtpServerSession(TcpClient client) : base(client) { Recipients = new List(); SendResponse(ResponseCodes.C220, Configuration.Hostname + " Welcome to SimpleMail DotNetCore based AIO MailServer"); NewLine += SmtpServerSession_NewLine; } private void SmtpServerSession_NewLine(string line) { try { var command = new SmtpCommand(line); if (WaitForData) { #if DEBUG bool dataend = false; if (command.Command.Equals("DATAEND")) { dataend = true; } #endif FreeLine = true; if (!FreeLine && command.Command.Equals("FREELINE")) { FreeLine = true; return; } else if ((FreeLine && command.Command.Equals("JUSTADOT")) || dataend) { SendResponse(ResponseCodes.C250, "OK"); foreach (var r in Recipients) { var split = r.Split('@'); var name = split[0]; var domain = split[1]; using (var context = new MysqlDB()) { context.Database.EnsureCreated(); int accountId = 0; var dmn = context.Domains.Where(x => x.Domain.Equals(domain)); var domainidx = dmn.FirstOrDefault().Id; var res = context.Accounts.Where(x => x.Domain.Equals(domainidx) && x.Name.Equals(name)); if (res.Count() < 1) { var res2 = context.Aliases.Where(x => x.SourceName.Equals(name) && x.SourceDomain.Equals(domain)); if (res2.Count() < 1) { var res3 = context.Accounts.Where(x => x.Domain.Equals(domain) && x.CatchAll == true); if (res3.Count() < 1) { accountId = 0; } else { accountId = res3.FirstOrDefault().Id; } } else { accountId = res2.FirstOrDefault().DestinationAccount; } } else { accountId = res.FirstOrDefault().Id; } int folderid = 0; var res4 = context.Folders.Where(x => x.AccountId == accountId && x.StandardFolder == (int)StandardFolders.INBOX); if (res4.Count() < 1) { //ToDo ERROR folderid = 0; } else folderid = res4.FirstOrDefault().Id; var nm = new Mails() { AccountId = accountId, ReceiveDate = DateTime.Now, Data = Data, SendedByServerIp = IPEndPoint.Address.ToString(), From = MailFrom, To = r, Folder = folderid }; context.Mails.Add(nm); context.SaveChangesAsync(); } MailFromSet = false; Recipients.Clear(); WaitForData = false; return; } SendResponse(ResponseCodes.C250, "OK"); return; } else { Data += command.Command; foreach (var s in command.Parameters) { Data += " " + s; } Data += "\r\n"; FreeLine = false; } return; } switch (command.Command.ToUpper()) { case "EHLO": if (command.Parameters.Length < 1) { SendResponse(ResponseCodes.C501, "Hostname Required"); return; } SenderHostname = command.Parameters[0]; Initialized = true; SendExtensionResponse(Extensions.PIPELINING); if (Configuration.STARTTLS_Active) { #pragma warning disable CS0162 // Unerreichbarer Code wurde entdeckt. SendExtensionResponse(Extensions.STARTTLS); #pragma warning restore CS0162 // Unerreichbarer Code wurde entdeckt. } SendResponse(ResponseCodes.C250, "SIZE " + (Configuration.MaxMessageSizeInKb * 1000).ToString()); return; case "HELO": if (command.Parameters.Length < 1) { SendResponse(ResponseCodes.C501, "Hostname Required"); return; } SenderHostname = command.Parameters[0]; Initialized = true; SendResponse(ResponseCodes.C250, "OK"); return; case "RSET": //ToDo return; case "QUIT": SendResponse(ResponseCodes.C221, Configuration.Hostname + " closing transmission channel"); CloseAll(); return; } if (Initialized) { switch (command.Command.ToUpper()) { case "MAIL": if (command.Parameters.Length < 1) { SendResponse(ResponseCodes.C501); return; } if (!command.Parameters[0].ToUpper().StartsWith("FROM")) { SendResponse(ResponseCodes.C501); return; } if (command.Parameters.Length == 1) { var m = command.Parameters[0].Split(':'); if (m.Length != 2) { SendResponse(ResponseCodes.C501); return; } MailFrom = m[1]; } else if (command.Parameters.Length == 2) { MailFrom = command.Parameters[1]; } else { SendResponse(ResponseCodes.C501); return; } MailFrom.Replace("<", String.Empty); MailFrom.Replace(">", String.Empty); MailFromSet = true; SendResponse(ResponseCodes.C250, "OK"); return; } if (MailFromSet) { switch (command.Command.ToUpper()) { case "RCPT": if (command.Parameters.Length < 1) { SendResponse(ResponseCodes.C501); return; } if (!command.Parameters[0].ToUpper().StartsWith("TO")) { SendResponse(ResponseCodes.C501); return; } var rcpt = ""; if (command.Parameters.Length == 1) { var m = command.Parameters[0].Split(':'); if (m.Length != 2) { SendResponse(ResponseCodes.C501); return; } rcpt = m[1]; } else if (command.Parameters.Length == 2) { rcpt = command.Parameters[1]; } else { SendResponse(ResponseCodes.C501); return; } rcpt = rcpt.Replace("<", String.Empty); rcpt = rcpt.Replace(">", String.Empty); var split = rcpt.Split('@'); if (split.Length != 2) { SendResponse(ResponseCodes.C501); return; } using (var context = new MysqlDB()) { context.Database.EnsureCreated(); var res = context.Domains.Where(x => x.Domain.Equals(split[1])); if (res.Count() < 1) { SendResponse(ResponseCodes.C550, "No such user here"); return; } } Recipients.Add(rcpt); SendResponse(ResponseCodes.C250, "OK"); return; } if (Recipients.Count > 0) { switch (command.Command.ToUpper()) { case "DATA": SendResponse(ResponseCodes.C354, "Start mail input, end with ."); WaitForData = true; return; } } } SendResponse(ResponseCodes.C500, command.Command); //throw new NotImplementedException(); } } catch (Exception e) { Logging.AddException(e); SendResponse(ResponseCodes.C554, "internal error"); SendResponse(ResponseCodes.C221, "Closing Transmission"); CloseAll(); } } private void ClearFields() { //ToDo einbauen } } }