private static void Check()
        {
            Console.WriteLine("running precheck...");

            MongoServer mongoServer = MyMongoDB.GetServer();

            MongoDatabase mongoDatabase = mongoServer.GetDatabase("email");
            MongoCollection <LazyBsonDocument> mongoCollection = mongoDatabase.GetCollection <LazyBsonDocument>("mails");

            MongoCursor <LazyBsonDocument> mongoCursor = mongoCollection.FindAll();

            foreach (LazyBsonDocument bsonDocument in mongoCursor)
            {
                if (Options.Verbose)
                {
                    Console.WriteLine("checking email-id: " + bsonDocument["_id"].ToString());
                }
                try {
                    if (User.EMailExists(bsonDocument["RecipientTo"].AsString))
                    {
                        Console.WriteLine("user with email-address found: " + bsonDocument["RecipientTo"].AsString);
                        User newMailUser = new User();
                        newMailUser.RefreshById(User.GetIdByEMail(bsonDocument["RecipientTo"].AsString));
                        eMail mail = new eMail(bsonDocument);
                        mail.AssignToUser(newMailUser);
                    }
                } catch (Exception ex) {
                    logger.ErrorException(ex.Message, ex);
                }
            }

            Console.WriteLine("precheck finished...");
        }
Exemple #2
0
        public bool SaveToMongoDB()
        {
            if (!this.IsValid)
            {
                return(false);
            }

            logger.Info("Saving received eMail to Database.");

            string userDatabase = "email";

            if (this._user.IsLoggedIn)
            {
                userDatabase = "email_user_" + this._user.Id;
            }
            else if (User.EMailExists(this.RecipientTo))
            {
                string userId = User.GetIdByEMail(this.RecipientTo);
                if (userId != String.Empty)
                {
                    userDatabase = "email_user_" + userId;
                }
            }

            MongoDatabase   mongoDatabase   = this._mongoServer.GetDatabase(userDatabase);
            MongoCollection mongoCollection = mongoDatabase.GetCollection <eMailEntity>("mails");

            eMailEntity mailEntity = new eMailEntity {
                ClientName  = this.ClientName,
                Time        = this.Time,
                MailFrom    = this.MailFrom,
                Subject     = this.Subject,
                RecipientTo = this.RecipientTo,
                Message     = this.Message,
                HeaderFrom  = this.HeaderFrom,
                HeaderTo    = this.HeaderTo,
                HeaderDate  = this.HeaderDate,
                Folder      = this.Folder,
                RawHeader   = this.RawHeader
            };

            if (this.HeaderCc.Count > 0)
            {
                mailEntity.HeaderCc = this.HeaderCc;
            }
            if (this.HeaderReplyTo != null && this.HeaderReplyTo.Address != String.Empty)
            {
                mailEntity.HeaderReplyTo = this.HeaderReplyTo;
            }

            try {
                WriteConcernResult result = mongoCollection.Save(mailEntity, WriteConcern.Acknowledged);
                return(result.Ok);
            } catch (Exception e) {
                Console.WriteLine("MongoCollection.Save Exception: " + e.Message);
                return(false);
            }
        }
        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;
                }
            };
        }
        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;
                }
            };
        }