dotnet-core_mail-server/MailServer/SMTPServer/SmtpServerSession.cs
2016-12-09 15:41:35 +01:00

320 lines
13 KiB
C#

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<string> 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<string>();
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 <CRLF>.<CRLF>");
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
}
}
}