/// <summary> /// Writes error to error log file. /// </summary> /// <param name="virtualServer">Virtual server name.</param> /// <param name="errorText">Error text to dump.</param> public static void DumpError(string virtualServer, string errorText) { try{ DataSet ds = new DataSet("dsEvents"); ds.Tables.Add("Events"); ds.Tables["Events"].Columns.Add("ID"); ds.Tables["Events"].Columns.Add("VirtualServer"); ds.Tables["Events"].Columns.Add("CreateDate", typeof(DateTime)); ds.Tables["Events"].Columns.Add("Type"); ds.Tables["Events"].Columns.Add("Text"); if (File.Exists(SCore.PathFix(m_Path + "Settings\\Events.xml"))) { ds.ReadXml(SCore.PathFix(m_Path + "Settings\\Events.xml")); } DataRow dr = ds.Tables["Events"].NewRow(); dr["ID"] = Guid.NewGuid().ToString(); dr["VirtualServer"] = virtualServer; dr["CreateDate"] = DateTime.Now; dr["Type"] = 0; dr["Text"] = errorText; ds.Tables["Events"].Rows.Add(dr); ds.WriteXml(SCore.PathFix(m_Path + "Settings\\Events.xml")); } catch { } }
/// <summary> /// Posts message to web page via HTTP. /// </summary> private void Post() { try { WebClient http = new WebClient(); http.Headers.Add("Content-Type", "multipart/form-data; boundary=---------------------8c808e3aebd9294"); string header = "-----------------------8c808e3aebd9294\r\n"; header += "Content-Disposition: form-data; name=\"file\"; filename=\"mail.eml\"\r\n"; header += "Content-Type: application/octet-stream\r\n"; header += "\r\n"; MemoryStream ms = new MemoryStream(); byte[] buffer = System.Text.Encoding.Default.GetBytes(header); ms.Write(buffer, 0, buffer.Length); SCore.StreamCopy(m_pMessage, ms); buffer = System.Text.Encoding.Default.GetBytes("\r\n-----------------------8c808e3aebd9294--\r\n"); ms.Write(buffer, 0, buffer.Length); byte[] response = http.UploadData(m_Url, ms.ToArray()); } catch (Exception x) { Error.DumpError(x, new System.Diagnostics.StackTrace()); } }
/// <summary> /// Loads specified virtual server API. /// </summary> /// <param name="assembly">API assembly name.</param> /// <param name="type">API type name.</param> /// <param name="initString">API init string</param> /// <returns></returns> internal IMailServerApi LoadApi(string assembly, string type, string initString) { string apiAssemblyPath = ""; if (File.Exists(SCore.PathFix(m_StartupPath + "\\" + assembly))) { apiAssemblyPath = SCore.PathFix(m_StartupPath + "\\" + assembly); } else { apiAssemblyPath = SCore.PathFix(assembly); } Assembly ass = Assembly.LoadFile(apiAssemblyPath); return((IMailServerApi)Activator.CreateInstance(ass.GetType(type), new object[] { initString })); }
/// <summary> /// Default constructor. /// </summary> /// <param name="server">FTP server.</param> /// <param name="port">FTP server port.</param> /// <param name="user">User name.</param> /// <param name="password">Password.</param> /// <param name="folder">FTP folder.</param> /// <param name="data">Data to store to server.</param> /// <param name="fileName">File name to add to stored data.</param> public _MessageRuleAction_FTP_AsyncSend(string server, int port, string user, string password, string folder, Stream data, string fileName) { m_Server = server; m_Port = port; m_User = user; m_Password = password; m_Folder = folder; m_FileName = fileName; m_DataStream = new MemoryStream(); // We need to use copy of message SCore.StreamCopy(data, m_DataStream); m_DataStream.Position = 0; Thread tr = new Thread(new ThreadStart(this.Send)); tr.Start(); }
/// <summary> /// Writes specified text to log file. /// </summary> /// <param name="fileName">Log file name.</param> /// <param name="text">Log text.</param> public static void WriteLog(string fileName, string text) { try{ fileName = SCore.PathFix(fileName); // If there isn't such directory, create it. if (!Directory.Exists(Path.GetDirectoryName(fileName))) { Directory.CreateDirectory(Path.GetDirectoryName(fileName)); } using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)){ StreamWriter w = new StreamWriter(fs); // create a Char writer w.BaseStream.Seek(0, SeekOrigin.End); // set the file pointer to the end w.Write(text + "\r\n"); w.Flush(); // update underlying file } } catch { } }
/// <summary> /// Executes specified actions. /// </summary> /// <param name="dvActions">Dataview what contains actions to be executed.</param> /// <param name="server">Reference to owner virtual server.</param> /// <param name="message">Recieved message.</param> /// <param name="sender">MAIL FROM: command value.</param> /// <param name="to">RCPT TO: commands values.</param> public GlobalMessageRuleActionResult DoActions(DataView dvActions, VirtualServer server, Stream message, string sender, string[] to) { // TODO: get rid of MemoryStream, move to Stream // bool messageChanged = false; bool deleteMessage = false; string storeFolder = null; string errorText = null; // Loop actions foreach (DataRowView drV in dvActions) { GlobalMessageRuleAction_enum action = (GlobalMessageRuleAction_enum)drV["ActionType"]; byte[] actionData = (byte[])drV["ActionData"]; // Reset stream position message.Position = 0; #region AutoResponse /* Description: Sends specified autoresponse message to sender. * Action data structure: * <ActionData> * <From></From> * <Message></Message> * </ActionData> */ if (action == GlobalMessageRuleAction_enum.AutoResponse) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); string smtp_from = table.GetValue("From"); string responseMsg = table.GetValue("Message"); // See if we have header field X-LS-MailServer-AutoResponse, never answer to auto response. MIME_h_Collection header = new MIME_h_Collection(new MIME_h_Provider()); header.Parse(new SmartStream(message, false)); if (header.Contains("X-LS-MailServer-AutoResponse")) { // Just skip } else { Mail_Message autoresponseMessage = Mail_Message.ParseFromByte(System.Text.Encoding.Default.GetBytes(responseMsg)); // Add header field 'X-LS-MailServer-AutoResponse:' autoresponseMessage.Header.Add(new MIME_h_Unstructured("X-LS-MailServer-AutoResponse", "")); // Update message date autoresponseMessage.Date = DateTime.Now; // Set To: if not explicity set if (autoresponseMessage.To == null || autoresponseMessage.To.Count == 0) { if (autoresponseMessage.To == null) { Mail_t_AddressList t = new Mail_t_AddressList(); t.Add(new Mail_t_Mailbox(null, sender)); autoresponseMessage.To = t; } else { autoresponseMessage.To.Add(new Mail_t_Mailbox(null, sender)); } } // Update Subject: variables, if any if (autoresponseMessage.Subject != null) { if (header.Contains("Subject")) { autoresponseMessage.Subject = autoresponseMessage.Subject.Replace("#SUBJECT", header.GetFirst("Subject").ValueToString().Trim()); } } // Sender missing, we can't send auto response. if (string.IsNullOrEmpty(sender)) { continue; } server.ProcessAndStoreMessage(smtp_from, new string[] { sender }, new MemoryStream(autoresponseMessage.ToByte(new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8)), null); } } #endregion #region Delete Message /* Description: Deletes message. * Action data structure: * <ActionData> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.DeleteMessage) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); deleteMessage = true; } #endregion #region ExecuteProgram /* Description: Executes specified program. * Action data structure: * <ActionData> * <Program></Program> * <Arguments></Arguments> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.ExecuteProgram) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); System.Diagnostics.ProcessStartInfo pInfo = new System.Diagnostics.ProcessStartInfo(); pInfo.FileName = table.GetValue("Program"); pInfo.Arguments = table.GetValue("Arguments"); pInfo.CreateNoWindow = true; System.Diagnostics.Process.Start(pInfo); } #endregion #region ForwardToEmail /* Description: Forwards email to specified email. * Action data structure: * <ActionData> * <Email></Email> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.ForwardToEmail) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); // See If message has X-LS-MailServer-ForwardedTo: and equals to "Email". // If so, then we have cross reference forward, don't forward that message MIME_h_Collection header = new MIME_h_Collection(new MIME_h_Provider()); header.Parse(new SmartStream(message, false)); bool forwardedAlready = false; if (header.Contains("X-LS-MailServer-ForwardedTo")) { foreach (MIME_h headerField in header["X-LS-MailServer-ForwardedTo"]) { if (headerField.ValueToString().Trim() == table.GetValue("Email")) { forwardedAlready = true; break; } } } // Reset stream position message.Position = 0; if (forwardedAlready) { // Just skip } else { // Add header field 'X-LS-MailServer-ForwardedTo:' MemoryStream msFwMessage = new MemoryStream(); byte[] fwField = System.Text.Encoding.Default.GetBytes("X-LS-MailServer-ForwardedTo: " + table.GetValue("Email") + "\r\n"); msFwMessage.Write(fwField, 0, fwField.Length); SCore.StreamCopy(message, msFwMessage); server.ProcessAndStoreMessage(sender, new string[] { table.GetValue("Email") }, msFwMessage, null); } } #endregion #region ForwardToHost /* Description: Forwards email to specified host. * All RCPT TO: recipients are preserved. * Action data structure: * <ActionData> * <Host></Host> * <Port></Port> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.ForwardToHost) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); foreach (string t in to) { message.Position = 0; server.RelayServer.StoreRelayMessage( Guid.NewGuid().ToString(), null, message, HostEndPoint.Parse(table.GetValue("Host") + ":" + table.GetValue("Port")), sender, t, null, SMTP_DSN_Notify.NotSpecified, SMTP_DSN_Ret.NotSpecified ); } message.Position = 0; } #endregion #region StoreToDiskFolder /* Description: Stores message to specified disk folder. * Action data structure: * <ActionData> * <Folder></Folder> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.StoreToDiskFolder) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); string folder = table.GetValue("Folder"); if (!folder.EndsWith("\\")) { folder += "\\"; } if (Directory.Exists(folder)) { using (FileStream fs = File.Create(folder + DateTime.Now.ToString("ddMMyyyyHHmmss") + "_" + Guid.NewGuid().ToString().Replace('-', '_').Substring(0, 8) + ".eml")){ SCore.StreamCopy(message, fs); } } else { // TODO: log error somewhere } } #endregion #region StoreToIMAPFolder /* Description: Stores message to specified IMAP folder. * Action data structure: * <ActionData> * <Folder></Folder> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.StoreToIMAPFolder) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); storeFolder = table.GetValue("Folder"); } #endregion #region AddHeaderField /* Description: Add specified header field to message main header. * Action data structure: * <ActionData> * <HeaderFieldName></HeaderFieldName> * <HeaderFieldValue></HeaderFieldValue> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.AddHeaderField) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); Mail_Message mime = Mail_Message.ParseFromStream(message); mime.Header.Add(new MIME_h_Unstructured(table.GetValue("HeaderFieldName"), table.GetValue("HeaderFieldValue"))); message.SetLength(0); mime.ToStream(message, new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8); // messageChanged = true; } #endregion #region RemoveHeaderField /* Description: Removes specified header field from message mian header. * Action data structure: * <ActionData> * <HeaderFieldName></HeaderFieldName> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.RemoveHeaderField) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); Mail_Message mime = Mail_Message.ParseFromStream(message); mime.Header.RemoveAll(table.GetValue("HeaderFieldName")); message.SetLength(0); mime.ToStream(message, new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8); // messageChanged = true; } #endregion #region SendErrorToClient /* Description: Sends error to currently connected client. NOTE: Error text may contain ASCII printable chars only and maximum length is 500. * Action data structure: * <ActionData> * <ErrorText></ErrorText> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.SendErrorToClient) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); errorText = table.GetValue("ErrorText"); } #endregion #region StoreToFTPFolder /* Description: Stores message to specified FTP server folder. * Action data structure: * <ActionData> * <Server></Server> * <Port></Server> * <User></User> * <Password></Password> * <Folder></Folder> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.StoreToFTPFolder) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); _MessageRuleAction_FTP_AsyncSend ftpSend = new _MessageRuleAction_FTP_AsyncSend( table.GetValue("Server"), Convert.ToInt32(table.GetValue("Port")), table.GetValue("User"), table.GetValue("Password"), table.GetValue("Folder"), message, DateTime.Now.ToString("ddMMyyyyHHmmss") + "_" + Guid.NewGuid().ToString().Replace('-', '_').Substring(0, 8) + ".eml" ); } #endregion #region PostToNNTPNewsGroup /* Description: Posts message to specified NNTP newsgroup. * Action data structure: * <ActionData> * <Server></Server> * <Port></Server> * <User></User> * <Password></Password> * <Newsgroup></Newsgroup> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.PostToNNTPNewsGroup) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); // Add header field "Newsgroups: newsgroup", NNTP server demands it. Mail_Message mime = Mail_Message.ParseFromStream(message); if (!mime.Header.Contains("Newsgroups:")) { mime.Header.Add(new MIME_h_Unstructured("Newsgroups:", table.GetValue("Newsgroup"))); } _MessageRuleAction_NNTP_Async nntp = new _MessageRuleAction_NNTP_Async( table.GetValue("Server"), Convert.ToInt32(table.GetValue("Port")), table.GetValue("Newsgroup"), new MemoryStream(mime.ToByte(new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8)) ); } #endregion #region PostToHTTP /* Description: Posts message to specified page via HTTP. * Action data structure: * <ActionData> * <URL></URL> * <FileName></FileName> * </ActionData> */ else if (action == GlobalMessageRuleAction_enum.PostToHTTP) { XmlTable table = new XmlTable("ActionData"); table.Parse(actionData); _MessageRuleAction_HTTP_Async http = new _MessageRuleAction_HTTP_Async( table.GetValue("URL"), message ); } #endregion } return(new GlobalMessageRuleActionResult(deleteMessage, storeFolder, errorText)); }
/// <summary> /// Checks if specified message matches to specified criteria. /// </summary> /// <param name="syntaxCheckOnly">Specifies if syntax check is only done. If true no matching is done.</param> /// <param name="r">Match expression reader what contains match expression.</param> /// <param name="mailFrom">SMTP MAIL FROM: command email value.</param> /// <param name="rcptTo">SMTP RCPT TO: command email values.</param> /// <param name="smtpSession">SMTP current session.</param> /// <param name="mime">Message to match.</param> /// <param name="messageSize">Message size in bytes.</param> /// <returns>Returns true if message matches to specified criteria.</returns> private bool Match(bool syntaxCheckOnly, LumiSoft.Net.StringReader r, string mailFrom, string[] rcptTo, SMTP_Session smtpSession, Mail_Message mime, int messageSize) { /* Possible keywords order * At first there can be NOT,parethesized or matcher * After NOT, parethesized or matcher * After matcher, AND or OR * After OR, NOT,parethesized or matcher * After AND, NOT,parethesized or matcher * After parethesized, NOT or matcher */ PossibleClauseItem possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.NOT | PossibleClauseItem.Matcher; bool lastMatchValue = false; // Empty string passed r.ReadToFirstChar(); if (r.Available == 0) { throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !"); } // Parse while there are expressions or get error while (r.Available > 0) { r.ReadToFirstChar(); // Syntax check must consider that there is alwas match !!! if (syntaxCheckOnly) { lastMatchValue = true; } #region () Groupped matchers // () Groupped matchers if (r.StartsWith("(")) { lastMatchValue = Match(syntaxCheckOnly, new LumiSoft.Net.StringReader(r.ReadParenthesized()), mailFrom, rcptTo, smtpSession, mime, messageSize); possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher | PossibleClauseItem.NOT; } #endregion #region AND clause // AND clause else if (r.StartsWith("and", false)) { // See if AND allowed if ((possibleClauseItems & PossibleClauseItem.AND) == 0) { throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !"); } // Last match value is false, no need to check next conditions if (!lastMatchValue) { return(false); } // Remove AND r.ReadWord(); r.ReadToFirstChar(); lastMatchValue = Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize); possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher | PossibleClauseItem.NOT; } #endregion #region OR clause // OR clause else if (r.StartsWith("or", false)) { // See if OR allowed if ((possibleClauseItems & PossibleClauseItem.OR) == 0) { throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !"); } // Remove OR r.ReadWord(); r.ReadToFirstChar(); // Last match value is false, then we need to check next condition. // Otherwise OR is matched already, just eat next matcher. if (lastMatchValue) { // Skip next clause Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize); } else { lastMatchValue = Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize); } possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher | PossibleClauseItem.NOT; } #endregion #region NOT clause // NOT clause else if (r.StartsWith("not", false)) { // See if NOT allowed if ((possibleClauseItems & PossibleClauseItem.NOT) == 0) { throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected !"); } // Remove NOT r.ReadWord(); r.ReadToFirstChar(); // Just reverse match result value lastMatchValue = !Match(syntaxCheckOnly, r, mailFrom, rcptTo, smtpSession, mime, messageSize); possibleClauseItems = PossibleClauseItem.Parenthesizes | PossibleClauseItem.Matcher; } #endregion else { // See if matcher allowed if ((possibleClauseItems & PossibleClauseItem.Matcher) == 0) { throw new Exception("Invalid syntax: '" + ClauseItemsToString(possibleClauseItems) + "' expected ! \r\n\r\n Near: '" + r.OriginalString.Substring(0, r.Position) + "'"); } // 1) matchsource // 2) keyword // Read match source string word = r.ReadWord(); if (word == null) { throw new Exception("Invalid syntax: matcher is missing !"); } word = word.ToLower(); string[] matchSourceValues = new string[] {}; #region smtp.mail_from // SMTP command MAIL FROM: value. // smtp.mail_from if (word == "smtp.mail_from") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { mailFrom }; } } #endregion #region smtp.rcpt_to // SMTP command RCPT TO: values. // smtp.mail_to else if (word == "smtp.rcpt_to") { if (!syntaxCheckOnly) { matchSourceValues = rcptTo; } } #endregion #region smtp.ehlo // SMTP command EHLO/HELO: value. // smtp.ehlo else if (word == "smtp.ehlo") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { smtpSession.EhloHost }; } } #endregion #region smtp.authenticated // Specifies if SMTP session is authenticated. // smtp.authenticated else if (word == "smtp.authenticated") { if (!syntaxCheckOnly) { if (smtpSession != null) { matchSourceValues = new string[] { smtpSession.IsAuthenticated.ToString() }; } } } #endregion #region smtp.user // SMTP authenticated user name. Empy string "" if not authenticated. // smtp.user else if (word == "smtp.user") { if (!syntaxCheckOnly) { if (smtpSession != null && smtpSession.AuthenticatedUserIdentity != null) { matchSourceValues = new string[] { smtpSession.AuthenticatedUserIdentity.Name }; } } } #endregion #region smtp.remote_ip // SMTP session connected client IP address. // smtp.remote_ip else if (word == "smtp.remote_ip") { if (!syntaxCheckOnly) { if (smtpSession != null) { matchSourceValues = new string[] { smtpSession.RemoteEndPoint.Address.ToString() }; } } } #endregion #region message.size // Message size in bytes. // message.size else if (word == "message.size") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { messageSize.ToString() }; } } #endregion #region message.header <SP> "HeaderFieldName:" // Message main header header field. If multiple header fields, then all are checked. // message.header <SP> "HeaderFieldName:" else if (word == "message.header") { string headerFieldName = r.ReadWord(); if (headerFieldName == null) { throw new Exception("Match source MainHeaderField HeaderFieldName is missing ! Syntax:{MainHeaderField <SP> \"HeaderFieldName:\"}"); } if (!syntaxCheckOnly) { if (mime.Header.Contains(headerFieldName)) { MIME_h[] fields = mime.Header[headerFieldName]; matchSourceValues = new string[fields.Length]; for (int i = 0; i < matchSourceValues.Length; i++) { matchSourceValues[i] = fields[i].ValueToString(); } } } } #endregion #region message.all_headers <SP> "HeaderFieldName:" // Any mime entity header header field. If multiple header fields, then all are checked. // message.all_headers <SP> "HeaderFieldName:" else if (word == "message.all_headers") { string headerFieldName = r.ReadWord(); if (headerFieldName == null) { throw new Exception("Match source MainHeaderField HeaderFieldName is missing ! Syntax:{MainHeaderField <SP> \"HeaderFieldName:\"}"); } if (!syntaxCheckOnly) { List <string> values = new List <string>(); foreach (MIME_Entity entity in mime.AllEntities) { if (entity.Header.Contains(headerFieldName)) { MIME_h[] fields = entity.Header[headerFieldName]; for (int i = 0; i < fields.Length; i++) { values.Add(fields[i].ValueToString()); } } } matchSourceValues = values.ToArray(); } } #endregion #region message.body_text // Message body text. // message.body_text else if (word == "message.body_text") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { mime.BodyText }; } } #endregion #region message.body_html // Message body html. // message.body_html else if (word == "message.body_html") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { mime.BodyHtmlText }; } } #endregion #region message.content_md5 // Message any mime entity decoded data MD5 hash. // message.content_md5 else if (word == "message.content_md5") { if (!syntaxCheckOnly) { List <string> values = new List <string>(); foreach (MIME_Entity entity in mime.AllEntities) { try{ if (entity.Body is MIME_b_SinglepartBase) { byte[] data = ((MIME_b_SinglepartBase)entity.Body).Data; if (data != null) { System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); values.Add(System.Text.Encoding.Default.GetString(md5.ComputeHash(data))); } } } catch { // Message data parsing failed, just skip that entity md5 } } matchSourceValues = values.ToArray(); } } #endregion #region sys.date_time // System current date time. Format: yyyy.MM.dd HH:mm:ss. // sys.date_time else if (word == "sys.date_time") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") }; } } #endregion #region sys.date // System current date. Format: yyyy.MM.dd. // sys.date else if (word == "sys.date") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { DateTime.Today.ToString("dd.MM.yyyy") }; } } #endregion #region sys.time // System current time. Format: HH:mm:ss. // sys.time else if (word == "sys.time") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { DateTime.Now.ToString("HH:mm:ss") }; } } #endregion #region sys.day_of_week // Day of week. Days: sunday,monday,tuesday,wednesday,thursday,friday,saturday. // sys.day_of_week else if (word == "sys.day_of_week") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { DateTime.Today.DayOfWeek.ToString() }; } } #endregion /* * // Day of month. Format: 1 - 31. If no so much days in month, then replaced with month max days. * // sys.day_of_month * else if(word == "sys.day_of_month"){ * } */ #region sys.day_of_year // Month of year. Format: 1 - 12. // sys.day_of_year else if (word == "sys.day_of_year") { if (!syntaxCheckOnly) { matchSourceValues = new string[] { DateTime.Today.ToString("M") }; } } #endregion #region Unknown // Unknown else { throw new Exception("Unknown match source '" + word + "' !"); } #endregion /* If we reach so far, then we have valid match sorce and compare value. * Just do compare. */ // Reset lastMatch result lastMatchValue = false; // Read matcher word = r.ReadWord(true, new char[] { ' ' }, true); if (word == null) { throw new Exception("Invalid syntax: operator is missing ! \r\n\r\n Near: '" + r.OriginalString.Substring(0, r.Position) + "'"); } word = word.ToLower(); #region * <SP> "astericPattern" // * <SP> "astericPattern" if (word == "*") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (SCore.IsAstericMatch(val, matchSourceValue.ToLower())) { lastMatchValue = true; break; } } } } #endregion #region !* <SP> "astericPattern" // !* <SP> "astericPattern" else if (word == "!*") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (SCore.IsAstericMatch(val, matchSourceValue.ToLower())) { lastMatchValue = false; break; } } } } #endregion #region == <SP> "value" // == <SP> "value" else if (word == "==") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (val == matchSourceValue.ToLower()) { lastMatchValue = true; break; } } } } #endregion #region != <SP> "value" // != <SP> "value" else if (word == "!=") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found, then already value equals foreach (string matchSourceValue in matchSourceValues) { if (val == matchSourceValue.ToLower()) { lastMatchValue = false; break; } lastMatchValue = true; } } } #endregion #region >= <SP> "value" // >= <SP> "value" else if (word == ">=") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (matchSourceValue.ToLower().CompareTo(val) >= 0) { lastMatchValue = true; break; } } } } #endregion #region <= <SP> "value" // <= <SP> "value" else if (word == "<=") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (matchSourceValue.ToLower().CompareTo(val) <= 0) { lastMatchValue = true; break; } } } } #endregion #region > <SP> "value" // > <SP> "value" else if (word == ">") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (matchSourceValue.ToLower().CompareTo(val) > 0) { lastMatchValue = true; break; } } } } #endregion #region < <SP> "value" // < <SP> "value" else if (word == "<") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (matchSourceValue.ToLower().CompareTo(val) < 0) { lastMatchValue = true; break; } } } } #endregion #region regex <SP> "value" // Regex <SP> "value" else if (word == "regex") { string val = r.ReadWord(); if (val == null) { throw new Exception("Invalid syntax: <SP> \"value\" is missing !"); } val = val.ToLower(); if (!syntaxCheckOnly) { // We check matchSourceValues when first is found foreach (string matchSourceValue in matchSourceValues) { if (Regex.IsMatch(val, matchSourceValue.ToLower())) { lastMatchValue = true; break; } } } } #endregion #region Unknown // Unknown else { throw new Exception("Unknown keword '" + word + "' !"); } #endregion possibleClauseItems = PossibleClauseItem.AND | PossibleClauseItem.OR; } } return(lastMatchValue); }
/// <summary> /// Loads virtual server from xml file. /// </summary> internal void LoadVirtualServers() { try{ if (!File.Exists(SCore.PathFix(m_StartupPath + "Settings\\localServers.xml"))) { return; } DateTime dateServers = File.GetLastWriteTime(SCore.PathFix(m_StartupPath + "Settings\\localServers.xml")); if (DateTime.Compare(dateServers, m_ServersFileDate) != 0) { m_ServersFileDate = dateServers; DataSet ds = new DataSet(); ds.Tables.Add("Servers"); ds.Tables["Servers"].Columns.Add("ID"); ds.Tables["Servers"].Columns.Add("Enabled"); ds.Tables["Servers"].Columns.Add("Name"); ds.Tables["Servers"].Columns.Add("API_assembly"); ds.Tables["Servers"].Columns.Add("API_class"); ds.Tables["Servers"].Columns.Add("API_initstring"); ds.ReadXml(SCore.PathFix(m_StartupPath + "Settings\\localServers.xml")); if (ds.Tables.Contains("Servers")) { // Delete running virtual servers what has deleted. for (int i = 0; i < m_pVirtualServers.Count; i++) { VirtualServer server = m_pVirtualServers[i]; bool exists = false; foreach (DataRow dr in ds.Tables["Servers"].Rows) { if (server.ID == dr["ID"].ToString()) { exists = true; break; } } if (!exists) { server.Stop(); m_pVirtualServers.Remove(server); i--; } } // Add new added virtual servers what aren't running already. foreach (DataRow dr in ds.Tables["Servers"].Rows) { //--- See if specified server already running, if so, skip it. --// bool exists = false; foreach (VirtualServer server in m_pVirtualServers) { if (server.ID == dr["ID"].ToString()) { exists = true; server.Enabled = ConvertEx.ToBoolean(dr["Enabled"], true); break; } } if (exists) { continue; } //--------------------------------------------------------------// string id = dr["ID"].ToString(); string name = dr["Name"].ToString(); string assembly = dr["API_assembly"].ToString(); string apiClass = dr["API_class"].ToString(); string intiStr = dr["API_initstring"].ToString(); IMailServerApi api = LoadApi(assembly, apiClass, intiStr); VirtualServer virtualServer = new VirtualServer(this, id, name, intiStr, api); m_pVirtualServers.Add(virtualServer); virtualServer.Enabled = ConvertEx.ToBoolean(dr["Enabled"], true); } } } } catch (Exception x) { Error.DumpError(x, new System.Diagnostics.StackTrace()); } }
/// <summary> /// Creates delivery status notifications(DSN) message. /// </summary> /// <param name="to">DSN message To.</param> /// <param name="subject">DSN message subject.</param> /// <param name="rtfText">DSN message RTF body text.</param> /// <param name="envelopeID">Envelope ID(MAIL FROM: ENVID).</param> /// <param name="arrivalDate">Message arrival date.</param> /// <param name="receivedFromMTA">The remote host EHLo name from where messages was received.</param> /// <param name="reportingMTA">Reporting MTA name.</param> /// <param name="originalRecipient">Original recipient(RCPT TO: ORCTP).</param> /// <param name="finalRecipient">Final recipient.</param> /// <param name="action">DSN action.</param> /// <param name="statusCode_text">Remote SMTP status code with text.</param> /// <param name="remoteMTA">Remote MTA what returned <b>statusCode_text</b>.</param> /// <param name="lastAttempt">Last delivery attempt.</param> /// <param name="retryUntil">Date time how long server will attempt to deliver message.</param> /// <param name="ret">Specifies what original message part are renturned.</param> /// <param name="message">Original message.</param> /// <returns>Returns created DSN message.</returns> public static Mail_Message CreateDsnMessage(string to, string subject, string rtfText, string envelopeID, DateTime arrivalDate, string receivedFromMTA, string reportingMTA, string originalRecipient, string finalRecipient, string action, string statusCode_text, string remoteMTA, DateTime lastAttempt, DateTime retryUntil, SMTP_DSN_Ret ret, Mail_Message message) { // For more info, see RFC 3464. // Ensure that all line-feeds are CRLF. rtfText = rtfText.Replace("\r\n", "\n").Replace("\n", "\r\n"); Mail_Message msg = new Mail_Message(); msg.MimeVersion = "1.0"; msg.Date = DateTime.Now; msg.From = new Mail_t_MailboxList(); msg.From.Add(new Mail_t_Mailbox("Mail Delivery Subsystem", "postmaster@local")); msg.To = new Mail_t_AddressList(); msg.To.Add(new Mail_t_Mailbox(null, to)); msg.Subject = subject; //--- multipart/report ------------------------------------------------------------------------------------------------- MIME_h_ContentType contentType_multipartReport = new MIME_h_ContentType(MIME_MediaTypes.Multipart.report); contentType_multipartReport.Parameters["report-type"] = "delivery-status"; contentType_multipartReport.Param_Boundary = Guid.NewGuid().ToString().Replace('-', '.'); MIME_b_MultipartReport multipartReport = new MIME_b_MultipartReport(contentType_multipartReport); msg.Body = multipartReport; //--- multipart/alternative ----------------------------------------------------------------------------------------- MIME_Entity entity_multipart_alternative = new MIME_Entity(); MIME_h_ContentType contentType_multipartAlternative = new MIME_h_ContentType(MIME_MediaTypes.Multipart.alternative); contentType_multipartAlternative.Param_Boundary = Guid.NewGuid().ToString().Replace('-', '.'); MIME_b_MultipartAlternative multipartAlternative = new MIME_b_MultipartAlternative(contentType_multipartAlternative); entity_multipart_alternative.Body = multipartAlternative; multipartReport.BodyParts.Add(entity_multipart_alternative); //--- text/plain --------------------------------------------------------------------------------------------------- MIME_Entity entity_text_plain = new MIME_Entity(); MIME_b_Text text_plain = new MIME_b_Text(MIME_MediaTypes.Text.plain); entity_text_plain.Body = text_plain; text_plain.SetText(MIME_TransferEncodings.QuotedPrintable, Encoding.UTF8, SCore.RtfToText(rtfText)); multipartAlternative.BodyParts.Add(entity_text_plain); //--- text/html ----------------------------------------------------------------------------------------------------- MIME_Entity entity_text_html = new MIME_Entity(); MIME_b_Text text_html = new MIME_b_Text(MIME_MediaTypes.Text.html); entity_text_html.Body = text_html; text_html.SetText(MIME_TransferEncodings.QuotedPrintable, Encoding.UTF8, SCore.RtfToHtml(rtfText)); multipartAlternative.BodyParts.Add(entity_text_html); //--- message/delivery-status MIME_Entity entity_message_deliveryStatus = new MIME_Entity(); MIME_b_Message body_message_deliveryStatus = new MIME_b_Message(MIME_MediaTypes.Message.delivery_status); entity_message_deliveryStatus.Body = body_message_deliveryStatus; StringBuilder dsnText = new StringBuilder(); if (!string.IsNullOrEmpty(envelopeID)) { dsnText.Append("Original-Envelope-Id: " + envelopeID + "\r\n"); } dsnText.Append("Arrival-Date: " + MIME_Utils.DateTimeToRfc2822(arrivalDate) + "\r\n"); if (!string.IsNullOrEmpty(receivedFromMTA)) { dsnText.Append("Received-From-MTA: dns; " + receivedFromMTA + "\r\n"); } dsnText.Append("Reporting-MTA: dns; " + reportingMTA + "\r\n"); dsnText.Append("\r\n"); if (!string.IsNullOrEmpty(originalRecipient)) { dsnText.Append("Original-Recipient: " + originalRecipient + "\r\n"); } dsnText.Append("Final-Recipient: rfc822;" + finalRecipient + "" + "\r\n"); dsnText.Append("Action: " + action + "\r\n"); dsnText.Append("Status: " + statusCode_text.Substring(0, 1) + ".0.0" + "\r\n"); if (!string.IsNullOrEmpty(statusCode_text)) { dsnText.Append("Diagnostic-Code: smtp; " + statusCode_text + "\r\n"); } if (!string.IsNullOrEmpty(remoteMTA)) { dsnText.Append("Remote-MTA: dns; " + remoteMTA + "\r\n"); } if (lastAttempt != DateTime.MinValue) { dsnText.Append("Last-Attempt-Date: " + MIME_Utils.DateTimeToRfc2822(lastAttempt) + "\r\n"); } if (retryUntil != DateTime.MinValue) { dsnText.Append("Will-Retry-Until: " + MIME_Utils.DateTimeToRfc2822(retryUntil) + "\r\n"); } dsnText.Append("\r\n"); body_message_deliveryStatus.SetData(new MemoryStream(Encoding.UTF8.GetBytes(dsnText.ToString())), MIME_TransferEncodings.EightBit); multipartReport.BodyParts.Add(entity_message_deliveryStatus); //--- message/rfc822 if (message != null) { MIME_Entity entity_message_rfc822 = new MIME_Entity(); MIME_b_MessageRfc822 body_message_rfc822 = new MIME_b_MessageRfc822(); entity_message_rfc822.Body = body_message_rfc822; if (ret == SMTP_DSN_Ret.FullMessage) { body_message_rfc822.Message = message; } else { MemoryStream ms = new MemoryStream(); message.Header.ToStream(ms, null, null); ms.Position = 0; body_message_rfc822.Message = Mail_Message.ParseFromStream(ms); } multipartReport.BodyParts.Add(entity_message_rfc822); } return(msg); }