diff --git a/MailServer/MailServer/Configuration.cs b/MailServer/MailServer/Configuration.cs new file mode 100644 index 0000000..d3db0d5 --- /dev/null +++ b/MailServer/MailServer/Configuration.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MailServer +{ + public class Configuration + { + public const string Hostname = "localhost"; + public bool STARTTLS_Active = false; + } +} diff --git a/MailServer/MailServer/Database.cs b/MailServer/MailServer/Database.cs index e2d2d42..9e657e3 100644 --- a/MailServer/MailServer/Database.cs +++ b/MailServer/MailServer/Database.cs @@ -1,6 +1,7 @@ using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.IO; using System.Linq; using System.Text; @@ -18,6 +19,12 @@ namespace SMTPServer public DbSet Accounts { get; set; } + public DbSet Folders { get; set; } + + public DbSet Aliases { get; set; } + + public DbSet Mails { get; set; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseMySql(@"Server=" + Hostname + ";database=" + DatabaseName + ";uid=" + Uid + ";pwd=" + Pwd + ";"); } @@ -32,9 +39,55 @@ namespace SMTPServer public class Accounts { public int Id { get; set; } + [MaxLength(255)] public string Name { get; set; } public int Domain { get; set; } public string Password { get; set; } + public bool CatchAll { get; set; } public bool Active { get; set; } } + + public class Folders + { + public int Id { get; set; } + public int AccountId { get; set; } + [MaxLength(100)] + public string Name { get; set; } + public int StandardFolder { get; set; } + } + + public enum StandardFolders + { + INBOX = 1, + TRASH = 2, + SPAM = 3 + } + + public class Aliases + { + public int Id { get; set; } + [MaxLength(255)] + public string SourceName { get; set; } + public int SourceDomain { get; set; } + public int DestinationAccount { get; set; } + } + + public class Mails + { + public int Id { get; set; } + public int AccountId { get; set; } + public DateTime ReceiveDate { get; set; } + public string Data { get; set; } + + [MaxLength(15)] + public string SendedByServerIp { get; set; } + + [MaxLength(255)] + public string From { get; set; } + + [MaxLength(255)] + public string To { get; set; } + public int Folder { get; set; } + public bool Readed { get; set; } + } } \ No newline at end of file diff --git a/MailServer/MailServer/DatabaseHelper.cs b/MailServer/MailServer/DatabaseHelper.cs new file mode 100644 index 0000000..566f16b --- /dev/null +++ b/MailServer/MailServer/DatabaseHelper.cs @@ -0,0 +1,52 @@ +using MailServer.Exceptions; +using SMTPServer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MailServer +{ + class DatabaseHelper + { + MysqlDB DBContext; + public DatabaseHelper() + { + DBContext = new MysqlDB(); + DBContext.Database.EnsureCreatedAsync(); + } + + public Folders GetInboxFromAccount(int accountid) => GetStandardFolderFromAccount(accountid, StandardFolders.INBOX); + + public Folders GetStandardFolderFromAccount(int accountid, StandardFolders folder) + { + var res = DBContext.Folders.Where(x => x.AccountId.Equals(accountid) && x.StandardFolder.Equals(folder)); + if (res.Count() < 1) throw new NotFoundException("Folder for specified account not found", Exceptions.Type.FOLDER); + return res.FirstOrDefault(); + } + + public Accounts GetAccount(string name, string domain) => GetAccount(name, GetDomain(domain).Id); + + public Accounts GetAccount(string name, int domain) + { + name = name.ToLower(); + var res = DBContext.Accounts.Where(x => x.Domain.Equals(domain) && x.Name.Equals(name)); + if (res.Count() < 1) throw new NotFoundException("no account found", Exceptions.Type.ACCOUNT); + return res.FirstOrDefault(); + } + + public Domains GetDomain(string domain) + { + domain = domain.ToLower(); + var res = DBContext.Domains.Where(x => x.Domain.Equals(domain)); + if (res.Count() < 1) throw new NotFoundException("no domain found", Exceptions.Type.DOMAIN); + return res.FirstOrDefault(); + } + + public void AddMail(Mails mail) + { + DBContext.Add(mail); + DBContext.SaveChangesAsync(); + } + } +} diff --git a/MailServer/MailServer/Exceptions/NotFoundException.cs b/MailServer/MailServer/Exceptions/NotFoundException.cs new file mode 100644 index 0000000..b3b989f --- /dev/null +++ b/MailServer/MailServer/Exceptions/NotFoundException.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MailServer.Exceptions +{ + class NotFoundException : Exception + { + public Type Type { get; set; } + + public NotFoundException(Type type) : base() + { + Type = type; + } + + public NotFoundException(string message, Type type) : base(message) + { + Type = type; + } + + public NotFoundException(string message, Exception inner, Type type) : base(message, inner) + { + Type = type; + } + } + + public enum Type + { + DOMAIN, + ACCOUNT, + ALIAS, + MAIL, + FOLDER + } +} diff --git a/MailServer/MailServer/GlobalSuppressions.cs b/MailServer/MailServer/GlobalSuppressions.cs deleted file mode 100644 index e7c317c..0000000 --- a/MailServer/MailServer/GlobalSuppressions.cs +++ /dev/null @@ -1,20 +0,0 @@ - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._Count")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._Mail")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._QueueEntered")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._DestinationIps")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._DestinationDnsNames")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._From")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._To")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._Subject")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._Others")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._Date")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._MessageId")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.Mail._MIME_Version")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._DestinationIndex")] - diff --git a/MailServer/MailServer/MTASession.cs b/MailServer/MailServer/MTASession.cs deleted file mode 100644 index d86b4df..0000000 --- a/MailServer/MailServer/MTASession.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace SMTPServer -{ - class MTASession - { - private static MTACommandsDict MTACommandsDict = new MTACommandsDict(); - private ConnectedEventArgs ConnectedEventArgs { get; set; } - - private bool Initialized { get; set; } - private string SenderHostname { get; set; } - - private bool AuthActive { get; set; } - private string Username { get; set; } - private string Password { get; set; } - private bool Authenticated { get; set; } - - private bool DATA { get; set; } - - private string Mail_From { get; set; } - - public MTASession(ConnectedEventArgs e) - { - ConnectedEventArgs = e; - Thread th = new Thread(new ThreadStart(StartCommunication)); - th.Start(); - } - - private void StartCommunication() - { - ConnectedEventArgs.SendResponse(ResponseCodes.C220, MailTransferAgent.Hostname); - ConnectedEventArgs.NewLine += ConnectedEventArgs_NewLine; - } - - private void ConnectedEventArgs_NewLine(string line) - { - if (line.StartsWith(MTACommandsDict[MTACommands.RSET])) - { - // Schauen was alles resettet wird - } - - if (!Initialized) - { - if (line.StartsWith(MTACommandsDict[MTACommands.HELO])) - { - ConnectedEventArgs.SendResponse(ResponseCodes.C250, MailTransferAgent.Hostname); - //} else if (line.StartsWith(MTACommandsDict[MTACommands.EHLO])) { - // ConnectedEventArgs.SendResponse(ResponseCodes.C250, MailTransferAgent.Hostname); - } - else - { - ConnectedEventArgs.SendResponse(ResponseCodes.C503, MailTransferAgent.Hostname); - return; - } - Initialized = true; - } - - if (line.StartsWith(MTACommandsDict[MTACommands.AUTH_LOGIN])) - { - AuthActive = true; - ConnectedEventArgs.SendResponse(ResponseCodes.C334); - } - else if (line.StartsWith(MTACommandsDict[MTACommands.MAIL_FROM])) - { - var args = line.Split(':'); - if (args.Length < 2) - { - ConnectedEventArgs.SendResponse(ResponseCodes.C501); - return; - } - var mailFrom = args[1]; - mailFrom.Replace('<', ' '); - } - else if (line.StartsWith(MTACommandsDict[MTACommands.QUIT])) - { - //throw new NotImplementedException(); - } else - { - ConnectedEventArgs.SendResponse(ResponseCodes.C500); - } - } - } -} diff --git a/MailServer/MailServer/Mail.cs b/MailServer/MailServer/Mail.cs index 19994f5..5d241ec 100644 --- a/MailServer/MailServer/Mail.cs +++ b/MailServer/MailServer/Mail.cs @@ -2,25 +2,20 @@ using System.Collections.Generic; using System.Text; -namespace SMTPServer +namespace MailServer { public class Mail { - public string To { get; private set; } public string From { get; private set; } + public string To { get; private set; } - public string Subject { get; private set; } - public string MessageId { get; private set; } - public string Date { get; private set; } + public string Data { get; set; } - public string MIME_Version { get; private set; } - - public string Others { get; private set; } - - - public Mail(string mail) + public Mail(string from, string to, string data) { - + From = from; + To = to; + Data = data; } public string GetSenderDomain() diff --git a/MailServer/MailServer/MailQueue.cs b/MailServer/MailServer/MailQueue.cs index 5d442fe..21d3c9b 100644 --- a/MailServer/MailServer/MailQueue.cs +++ b/MailServer/MailServer/MailQueue.cs @@ -1,9 +1,11 @@ using DnsClient; +using MailServer; +using SMTPServer; using SMTPServer.Exceptions; using System; using System.Collections.Generic; -namespace SMTPServer +namespace MailServer { public class MailQueue { @@ -11,8 +13,9 @@ namespace SMTPServer public static async void AddToMesssageQueueAsync(Mail mail) { +#pragma warning disable IDE0017 // Die Objektinitialisierung kann vereinfacht werden. var qmail = new QueueMail(mail); - +#pragma warning restore IDE0017 // Die Objektinitialisierung kann vereinfacht werden. qmail.DestinationDnsNames = await GetDNSEntries.GetMXRecordAsync(mail.GetSenderDomain()); qmail.DestinationIps = await GetDNSEntries.GetIPAddressFromDnsArrayAsync(qmail.DestinationDnsNames); diff --git a/MailServer/MailServer/MailServer.csproj b/MailServer/MailServer/MailServer.csproj index 5cc3a31..8987775 100644 --- a/MailServer/MailServer/MailServer.csproj +++ b/MailServer/MailServer/MailServer.csproj @@ -1,4 +1,4 @@ - + 1701;1702;1705;1006 @@ -18,13 +18,12 @@ - 1.0.0-beta-1011 - 1.0.0-preview2-1-003177 + 1.0.0-preview3-004056 1.1.0-preview4-final @@ -58,7 +57,7 @@ 1.1.0-rtm-10012 - 4.0.1 + 4.3.0 4.3.0 diff --git a/MailServer/MailServer/MailTransferAgent.cs b/MailServer/MailServer/MailTransferAgent.cs index d062a28..36e7ef4 100644 --- a/MailServer/MailServer/MailTransferAgent.cs +++ b/MailServer/MailServer/MailTransferAgent.cs @@ -4,12 +4,13 @@ using System.Text; using System.Threading; using SMTPServer.Exceptions; using System.Net; +using MailServer.SMTPServer; namespace SMTPServer { class MailTransferAgent { - public const string Hostname = "mail.fstamm.net"; + /* public const string Hostname = "mail.fstamm.net"; private static MTACommandsDict MTACommandsDict = new MTACommandsDict(); private static Thread Thread; private static List Sessions { get; set; } @@ -62,6 +63,6 @@ namespace SMTPServer { return null; - } + }*/ } } diff --git a/MailServer/MailServer/PortListener.cs b/MailServer/MailServer/PortListener.cs index 00bc4b0..f848deb 100644 --- a/MailServer/MailServer/PortListener.cs +++ b/MailServer/MailServer/PortListener.cs @@ -1,4 +1,5 @@ -using SMTPServer.Exceptions; +using MailServer.SMTPServer; +using SMTPServer.Exceptions; using System; using System.Collections.Generic; using System.Net; @@ -12,9 +13,7 @@ namespace SMTPServer public class ConnectedEventArgs : EventArgs { - public delegate void ReceivedLineEventHandler(string line); - - public event ReceivedLineEventHandler NewLine; + private Encoding Encoding { get; set; } private string Others { get; set; } @@ -71,7 +70,7 @@ namespace SMTPServer if (c.Equals('\n')) { Console.WriteLine(line); - NewLine(line); + //NewLine(line); line = ""; } else line += c; diff --git a/MailServer/MailServer/Program.cs b/MailServer/MailServer/Program.cs index 4adfa34..d55c044 100644 --- a/MailServer/MailServer/Program.cs +++ b/MailServer/MailServer/Program.cs @@ -35,8 +35,10 @@ namespace SMTPServer //t.Start(); //TestAsync(); - var listener = new PortListener(5122); - listener.OnConnected += Listener_OnConnected; + //var listener = new PortListener(5122); + //listener.OnConnected += Listener_OnConnected; + + var l = new MailServer.SMTPServer.SmtpPortListener(5122); while (true) { @@ -60,7 +62,7 @@ namespace SMTPServer private static void Listener_OnConnected(object source, ConnectedEventArgs e) { - var session = new MTASession(e); + //var session = new MTASession(e); //throw new NotImplementedException(); } /* diff --git a/MailServer/MailServer/MTACommands.cs b/MailServer/MailServer/SMTPServer/MTACommands.cs similarity index 98% rename from MailServer/MailServer/MTACommands.cs rename to MailServer/MailServer/SMTPServer/MTACommands.cs index aa5d791..537ace2 100644 --- a/MailServer/MailServer/MTACommands.cs +++ b/MailServer/MailServer/SMTPServer/MTACommands.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Text; -namespace SMTPServer +namespace MailServer.SMTPServer { public class MTACommandsDict : Dictionary { diff --git a/MailServer/MailServer/SMTPServer/SmtpCommand.cs b/MailServer/MailServer/SMTPServer/SmtpCommand.cs new file mode 100644 index 0000000..c31a8e3 --- /dev/null +++ b/MailServer/MailServer/SMTPServer/SmtpCommand.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MailServer.SMTPServer +{ + public class SmtpCommand + { + public string Command { get; set; } + public string[] Parameters { get; set; } + + public SmtpCommand(string command) + { + Parameters = new string[0]; + if (command.Length == 0) + { + Command = "FREELINE"; + return; + } + else if (command.Equals(".")) + { + Command = "JUSTADOT"; + return; + } +# if DEBUG + else if (command.Equals(".")) + { + Command = "DATAEND"; + return; + } +# endif + + var sp = command.Split(' '); + + Command = sp[0]; + + if (sp.Length < 2) return; + Parameters = new string[sp.Length - 1]; + for (int i = 1; i < sp.Length; i++) + { + Parameters[i - 1] = sp[i]; + } + } + } +} diff --git a/MailServer/MailServer/SMTPServer/SmtpPortListener.cs b/MailServer/MailServer/SMTPServer/SmtpPortListener.cs new file mode 100644 index 0000000..85d3ceb --- /dev/null +++ b/MailServer/MailServer/SMTPServer/SmtpPortListener.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace MailServer.SMTPServer +{ + public class SmtpPortListener + { + private static List Ports { get; set; } + private int Port { get; set; } + private TcpListener Listener; + private List Sessions { get; set; } + + public SmtpPortListener(int port) + { + Sessions = new List(); + Port = port; + Thread thread = new Thread(StartListeningAsync); + thread.Start(); + } + + public async void StartListeningAsync() + { + Listener = new TcpListener(IPAddress.Any, Port); + Listener.Start(); + + while (true) + { + //var socket = await Listener.AcceptSocketAsync(); + var client = await Listener.AcceptTcpClientAsync(); + var session = new SmtpServerSession(client); + Sessions.Add(session); + } + } + } +} diff --git a/MailServer/MailServer/SMTPServer/SmtpServerSession.cs b/MailServer/MailServer/SMTPServer/SmtpServerSession.cs new file mode 100644 index 0000000..8190e8d --- /dev/null +++ b/MailServer/MailServer/SMTPServer/SmtpServerSession.cs @@ -0,0 +1,297 @@ +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 + 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) + { + //ToDo unmöglich machen!! + } + 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 = "0.0.0.0", + From = MailFrom, + To = r, + Folder = folderid + }; + + context.Mails.Add(nm); + context.SaveChangesAsync(); + } + + return; + } + SendResponse(ResponseCodes.C250, "OK"); + return; + } + else + { + Data += command.Command; + + foreach (var s in command.Parameters) + { + Data += " " + s; + } + + Data += "\n"; + FreeLine = false; + } + return; + } + + switch (command.Command.ToUpper()) + { + 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 + } + + } +} diff --git a/MailServer/MailServer/SMTPServer/SmtpSession.cs b/MailServer/MailServer/SMTPServer/SmtpSession.cs new file mode 100644 index 0000000..184f944 --- /dev/null +++ b/MailServer/MailServer/SMTPServer/SmtpSession.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace MailServer.SMTPServer +{ + public delegate void ReceivedLineEventHandler(string line); + + class SmtpSession + { + public event ReceivedLineEventHandler NewLine; + + private TcpClient Client { get; set; } + private NetworkStream Stream { get; set; } + private Encoding Encoding = Encoding.ASCII; + private string Others; + private Thread Worker; + private bool Active = true; + + public SmtpSession(TcpClient client) + { + Client = client; + Stream = client.GetStream(); + Others = ""; + Worker = new Thread(ReadClientInput); + Worker.Start(); + } + + public void SendResponse(ResponseCodes responseCode) => SendResponse(responseCode, ""); + + public void SendResponse(ResponseCodes responseCode, string args) + { + var text = ((int)responseCode).ToString(); + text += " " + args +'\r' + '\n'; + var bytes = Encoding.UTF8.GetBytes(text); + Stream.Write(bytes, 0, bytes.Length); + } + + private void ReadClientInput() + { + while (Active) + { + if (Stream.DataAvailable) + { + byte[] buffer = new byte[Client.ReceiveBufferSize]; + var readed = Stream.Read(buffer, 0, buffer.Length); + + var str = Encoding.GetString(buffer, 0, readed); + lock (Others) + { + Others += str; + } + + CheckLines(); + } + else + { + Thread.Sleep(10); + } + } + } + + private bool r = false; + + private void CheckLines() + { + lock (Others) + { + var line = ""; + foreach (char c in Others) + { + if (c.Equals('\r')) + { + r = true; + } + else if (r && c.Equals('\n')) + { + //Console.WriteLine(line); + NewLine(line); + line = ""; + } + else + { + line += c; + r = false; + } + } + Others = line; + } + } + + public void CloseAll() + { + Stream.Dispose(); + Client.Dispose(); + Active = false; + } + } +} \ No newline at end of file