public void PurgeOldIncomingMailsFiles(IList <Guid> contentIds) { foreach (var contentId in contentIds) { try { IncomingMailDTO.DeleteContentFile(contentId); } catch { } } // Drop any missed mail folders var zombieThreshold = DateTime.UtcNow.AddMinutes(-2 * Configuration.Instance.TimeToLiveInMinutes); var incomingMailDirectory = new DirectoryInfo(Configuration.Instance.IncomingMailDirectory); foreach (var incomingMail in incomingMailDirectory.GetFiles()) { if (incomingMail.LastWriteTimeUtc < zombieThreshold) { try { File.Delete(incomingMail.FullName); } catch { } } } }
public Extractor(IDbConnection conn, IncomingMailDTO m) { _conn = conn; _m = m; }
private void ExtractIncomingMail(IDbConnection c, IncomingMailDTO m) { new Extractor(c, m).Extract(); }
private void DeleteIncomingMail(IDbConnection c, IncomingMailDTO m) { c.Execute("delete from IncomingMail where Id=@Id", m); m.DeleteContentFile(); }
private void DispatchIncomingMail(IDbConnection conn, IncomingMailDTO m) { conn.Execute("insert into IncomingMail (ReceivedOn,Recipient,Sender,ContentSize,ContentId) values (@ReceivedOn,@Recipient,@Sender,@ContentSize,@ContentId);", m); }
public void Enqueue(IncomingMailDTO m) { _queue.Add(m); }
private void HandleCompleteLine(ArraySegment <byte> line) { var isHandled = false; var nextState = _state; byte[] response = null; ArraySegment <byte> cmd = _emptyBuffer; var tokens = new ArraySegment <byte>[] { }; if (_state != SmtpState.WaitingForEndOfData) { tokens = Bytes.Split(line, Whitespace); if (tokens.Length > 0) { Bytes.ToUpper(tokens[0]); cmd = tokens[0]; } } if (Bytes.IsSame(RSET, cmd)) { isHandled = true; if (tokens.Length == 1) { ResetMailInfo(); response = ReplyOk; nextState = SmtpState.WaitingForHelo; } else { response = ReplySyntaxErrorRset; } } else if (_state == SmtpState.WaitingForHelo && Bytes.IsSame(EHLO, cmd)) { isHandled = true; if (tokens.Length == 2) { response = ReplyEhlo; nextState = SmtpState.WaitingForMailFrom; } else { response = ReplySyntaxErrorEhlo; } } else if (_state == SmtpState.WaitingForHelo && Bytes.IsSame(HELO, cmd)) { isHandled = true; if (tokens.Length == 2) { response = ReplyHelo; nextState = SmtpState.WaitingForMailFrom; } else { response = ReplySyntaxErrorHelo; } } else if (_state == SmtpState.WaitingForMailFrom && Bytes.IsSame(MAIL, cmd)) { isHandled = true; // extract mail address between < > after : bool go = false; int lt = -1, gt = -1; for (var i = line.Offset; i < line.Offset + line.Count; i++) { byte ch = line.Array[i]; if (go) { if (lt == -1 && ch == LessThan) { lt = i; } if (lt != -1 && ch == GreaterThan) { gt = i; break; } } else if (ch == SemiColon) { go = true; } } if (lt != -1 && gt != -1) { // sender found, _sender = Encoding.ASCII.GetString(line.Array, lt + 1, gt - lt - 1).Trim(); // check for optional SIZE=nnnnnnn extension after the sender int sizeOffset = Bytes.OffsetOf(MessageSizeExtension, line.Array, gt + 1, line.Count - gt - 1); if (sizeOffset != -1) { int valueBeginOffset = sizeOffset + MessageSizeExtension.Length; int valueEndOffset = -1; for (var i = valueBeginOffset; i < line.Offset + line.Count; i++) { byte ch = line.Array[i]; byte digit = Bytes.Digits[ch]; if (Whitespace.Contains(ch)) { break; } else if (digit > 9 || digit < 0) { valueEndOffset = -1; break; } valueEndOffset = i; } if (valueEndOffset >= valueBeginOffset) { int size = 0, scale = 1; for (var i = valueEndOffset; i >= valueBeginOffset && size < MaximumMessageSize; i--, scale *= 10) { size += Bytes.Digits[line.Array[i]] * scale; } if (size > MaximumMessageSize) { response = ReplyMessageSizeTooBig; nextState = SmtpState.WaitingForRset; } else { _mailContentExpectedSize = size; response = ReplyOk; nextState = SmtpState.WaitingForRcptTo; } } else { response = ReplySyntaxErrorMail; } } else { // no size extension response = ReplyOk; nextState = SmtpState.WaitingForRcptTo; } } else { response = ReplySyntaxErrorMail; } } else if ((_state == SmtpState.WaitingForRcptTo || _state == SmtpState.WaitingForAdditionalRcptTo) && Bytes.IsSame(RCPT, cmd)) { // standard deviation: send only to the last given recipient even if not pretending so. isHandled = true; // extract mail address between < > after : bool go = false; int lt = -1, gt = -1; for (var i = line.Offset; i < line.Offset + line.Count; i++) { byte ch = line.Array[i]; if (go) { if (lt == -1 && ch == LessThan) { lt = i; } if (lt != -1 && ch == GreaterThan) { gt = i; break; } } else if (ch == SemiColon) { go = true; } } if (lt != -1 && gt != -1) { var recipient = Encoding.ASCII.GetString(line.Array, lt + 1, gt - lt - 1).Trim().ToLowerInvariant(); if (_server.MailDispatcher.IsMailboxActive(recipient)) { _lastRecipient = recipient; response = ReplyOk; nextState = SmtpState.WaitingForAdditionalRcptTo; } else { response = ReplyNoSuchUserHere; } } else { response = ReplySyntaxErrorRcpt; } } else if (_state == SmtpState.WaitingForAdditionalRcptTo && Bytes.IsSame(DATA, cmd)) { isHandled = true; if (tokens.Length == 1) { response = ReplyStartMail; if (_mailContent == null) { // presize stream to avoid garbage & extra reallocation if expected size makes sense. // add a bit of slack for size errors var size = (_mailContentExpectedSize > 0 && _mailContentExpectedSize <= MaximumMessageSize) ? _mailContentExpectedSize + 1024 : 4096; _mailContentId = Guid.NewGuid(); _mailContent = new FileStream(IncomingMailDTO.GetContentFileName(_mailContentId), FileMode.CreateNew, FileAccess.Write, FileShare.None, 16384); } nextState = SmtpState.WaitingForEndOfData; } else { response = ReplySyntaxErrorData; } } else if (_state == SmtpState.WaitingForEndOfData) { isHandled = true; if (line.Count == EndOfMail.Length && Bytes.StartsWith(EndOfMail, line)) { if (_mailContent.Length <= MaximumMessageSize) { response = ReplyOk; nextState = SmtpState.WaitingForMailFrom; _mailContent.Flush(); _server.MailDispatcher.Enqueue(new IncomingMailDTO(DateTime.UtcNow, _lastRecipient, _sender, (int)_mailContent.Length, _mailContentId)); _mailContent.Dispose(); _mailContent = null; } else { response = ReplyMessageSizeTooBig; nextState = SmtpState.WaitingForRset; } ResetMailInfo(); } else { // accumulate mail body & handle dot unstuffing (while msg size doesn't exceed maximum size, since it will be discarded later anyway). int offset = line.Offset; int count = line.Count; if (line.Array[offset] == Dot) { offset++; count--; } if (_mailContent != null && _mailContent.Length + count <= MaximumMessageSize) { _mailContent.Write(line.Array, offset, count); } } } else if (Bytes.IsSame(QUIT, cmd)) { isHandled = true; if (tokens.Length == 1) { ResetMailInfo(); response = ReplyBye; nextState = SmtpState.Disconnect; } else { response = ReplySyntaxErrorQuit; } } else if (Bytes.IsSame(VRFY, cmd) || Bytes.IsSame(EXPN, cmd)) { isHandled = true; response = ReplyCommandNotImplemented; } else if (Bytes.IsSame(HELP, cmd)) { isHandled = true; response = ReplyHelp; } else if (Bytes.IsSame(NOOP, cmd)) { isHandled = true; response = ReplyOk; } if (!isHandled) { var isKnownCommand = KnownCommands.Any((knownCmd) => Bytes.IsSame(knownCmd, cmd)); response = isKnownCommand ? ReplyBadSequence : ReplyUnknownCommand; } _state = nextState; if (response != null && response.Length > 0) { var e = CreateArgs(SendCompleted, response); if (!_socket.SendAsync(e)) { SendCompleted(_socket, e); } } }