//------------------------------------------------------------------------------------------- public ArrayList CheckRCPT(SmtpClient smtpclient, Address address, bool AllowRelay) { if (AuthorizeRCPT != null) return AuthorizeRCPT(smtpclient, address, AllowRelay); else return null; }
//-------------------------------------------------------------------------------------------- /// <summary> /// This is where 90% of the magic happens. Once the SmtpClient is issued a recipient's address this event is /// triggered and handles the address to return an address list which specifies how to route the incoming message. /// </summary> /// <param name="smtpclient">This is the client triggering the authorization event.</param> /// <param name="address">This is the address being verified.</param> /// <param name="AllowRelay">This states whether or not the client is allowed to relay. (i.e. if the address is not local, then /// an address should be added to the address list to route the message to the remote server.</param> /// <returns>This event should return an address list that contains routing instructions for the message.</returns> private ArrayList server_AuthorizeRCPT(SmtpClient smtpclient, Address mailaddress, bool AllowRelay) { string sql = ""; ArrayList al = new ArrayList(); ADODB.Recordset rs = null; if (!DBOpen()) { Address address = new Address(); address.SetAddress(mailaddress.address); DebugOut("Database connection error, e-mail rejected.", true); address.EndPoint = AddressEndPointStatus.Bad; address.Error = "There is a problem on our side, we can not accept your mail due to a database connection error."; al.Add(address); return al; } try { sql = String.Format(sqldomaincheck, mailaddress.domain); rs = Query(sql); if (rs.EOF && AllowRelay) { Address address = new Address(); address.SetAddress(mailaddress.address); address.Path = address.address; address.EndPoint = AddressEndPointStatus.Forward; al.Add(address); return al; } else if (rs.EOF && !AllowRelay) { Address address = new Address(); address.SetAddress(mailaddress.address); address.Error = "This server is rejecting your mail because it is not an authority for the end address to which you are trying to send to and/or you are not authenticated for relay."; address.EndPoint = AddressEndPointStatus.Bad; al.Add(address); return al; } while (!rs.EOF) { Address address = new Address(); address.SetAddress(mailaddress.address); switch (Int32.Parse(rs.get_Collect("status").ToString())) { #region Case BLOCKED case (int)Status.Blocked: //domain disabled address.EndPoint = AddressEndPointStatus.Bad; address.Error = "This server is not allowed to handle mail to this address and therefore can not accept your mail."; al.Add(address); return al; #endregion #region Case NORMAL case (int)Status.Normal: //normal operation address = null; // address.EndPoint = AddressEndPoint.Local; break; #endregion #region Case REMOTE case (int)AddressEndPointStatus.Remote: // forward mail to specified server address.EndPoint = AddressEndPointStatus.Remote; address.Server = rs.get_Collect("misc").ToString(); al.Add(address); return al; #endregion #region Case FORWARD case (int)AddressEndPointStatus.Forward: address.Path = rs.get_Collect("misc").ToString(); address.EndPoint = AddressEndPointStatus.Forward; al.Add(address); return al; #endregion #region Case DEFAULT default: address.Error = "Server is misconfigured for this domain and therefore can not accept any mail."; DebugOut("Domain status settings for " + address.domain + " are not set properly please check them again.", true); al.Add(address); return al; #endregion } rs.MoveNext(); } string disposableprefix = "<#IGNORE#>"; bool prefixfound = false; bool disposablefound = false; if (mailaddress.prefix.IndexOf("-") > 0 && mailaddress.prefix.Length > mailaddress.prefix.IndexOf("-")) disposableprefix = mailaddress.prefix.Substring(0, mailaddress.prefix.IndexOf("-")); sql = String.Format(sqladdressa, mailaddress.prefix, mailaddress.domain, disposableprefix); rs = Query(sql); if (rs.EOF) { Address address = new Address(); address.EndPoint = AddressEndPointStatus.Bad; address.Error = "The address belongs to this server but no mail box for it exists. (" + mailaddress.address + ")"; al.Add(address); return al; } while (!rs.EOF) { string prefix = rs.Fields["prefix"].Value.ToString().ToLower(); string astatus = rs.Fields["status"].Value.ToString(); int status = (int)rs.Fields["status"].Value; if (prefix == mailaddress.prefix.ToLower()) { prefixfound = true; } if (prefix == disposableprefix && status == 7) { disposablefound = true; } rs.MoveNext(); } rs.MoveFirst(); int rowcount = 0; while (!rs.EOF) { rowcount++; string prefix = rs.Fields["prefix"].Value.ToString(); string misc = rs.Fields["misc"].Value.ToString(); if ((prefixfound || disposablefound) && prefix == "*") { rs.MoveNext(); continue; } else if (prefixfound && prefix == disposableprefix) { rs.MoveNext(); continue; } ADODB.Recordset rsb = null; Address address = new Address(); address.SetAddress(mailaddress.address); sql = ""; switch (Int32.Parse(rs.get_Collect("status").ToString())) { case (int)Status.Blocked: if (!(misc == "ignore" && prefix == disposableprefix)) { address.EndPoint = AddressEndPointStatus.Blocked; address.Error = "This user's mail box has been disabled."; al.Add(address); } else { address = null; } break; case (int)Status.Normal: sql = String.Format(sqladdressb, rs.get_Collect("mailboxid").ToString()); rsb = Query(sql); address.EndPoint = AddressEndPointStatus.Local; address.quota = Decimal.Parse(rsb.Fields["quota"].Value.ToString()); address.Path = server.MailPath + rsb.Fields["postoffice"].Value.ToString() + "\\" + rsb.Fields["mailbox"].Value.ToString() + "\\"; al.Add(address); break; case (int)Status.Forward: string fmisc = rs.Fields["misc"].Value.ToString().Replace(" ", ""); address.EndPoint = AddressEndPointStatus.Forward; address.Path = fmisc; al.Add(address); break; case (int)Status.Execute: sql = String.Format(sqladdressb, rs.get_Collect("mailboxid").ToString()); rs = Query(sql); address.quota = Decimal.Parse(rs.get_Collect("quota").ToString()); address.EndPoint = AddressEndPointStatus.Plugin; address.Path = server.MailPath + rs.Fields["postoffice"].Value.ToString() + "\\" + rs.Fields["mailbox"].Value + "\\"; al.Add(address); break; case (int)AddressEndPointStatus.AutoRespond: break; case (int)AddressEndPointStatus.Disposable: //no action - just a pointer record break; case (int)Status.Remote: string rmisc = rs.Fields["misc"].Value.ToString().Trim(); address.EndPoint = AddressEndPointStatus.Remote; address.Path = rmisc; al.Add(address); break; case (int)Status.SMS: sql = String.Format(sqlsms, rs.Fields["smsserviceid"].Value.ToString()); rsb = Query(sql); if (!rsb.EOF) { switch (Int32.Parse(rsb.Fields["type"].Value.ToString())) { case 1: address.EndPoint = AddressEndPointStatus.SMS; address.Path = rs.Fields["misc"].Value.ToString() + "@" + rsb.Fields["misc"].Value.ToString(); al.Add(address); break; case 2: address.EndPoint = AddressEndPointStatus.Forward; address.Path = rs.Fields["misc"].Value.ToString() + "@" + rsb.Fields["misc"].Value.ToString(); al.Add(address); break; case 3: address.EndPoint = AddressEndPointStatus.Plugin; address.Path = rsb.Fields["misc"].Value.ToString(); al.Add(address); break; } } break; default: DebugOut("The status set for " + address.address + " is invalid. E-mail to this address was rejected, please fix it.", true); address.EndPoint = AddressEndPointStatus.Bad; address.Error = "The mailbox you are trying to reach does exist for this user however it is incorrectly configured and we are forced to reject your e-mail."; al.Add(address); break; } rs.MoveNext(); } if (rowcount == 0) { Address address = new Address(); address.SetAddress(mailaddress.address); address.Error = "This server is authoritive for the domain that you are trying to send an e-mail to, however the mailbox that you are trying to reach does not exist on this server!"; address.EndPoint = AddressEndPointStatus.Bad; al.Add(address); } return al; } catch (Exception e) { Address address = new Address(); address.SetAddress(mailaddress.address); DebugOut("User check against database failed for " + mailaddress.address + ".\r\n\r\n" + e.Message, true); address.Error = "This server can not accept your e-mail due to a local database error."; address.EndPoint = AddressEndPointStatus.Bad; al.Add(address); return al; } }
//------------------------------------------------------------------------------------------- public void HandleData(string pData) { #region Parse Int int iSub = (pData.Length > 4) ? 4 : pData.Length; #endregion switch (pData.Substring(0, iSub).ToUpper()) { #region Case HELO case "HELO": myData.iState = 1; Send("250 Welcome to our server, spam is not welcome here." + newline); break; #endregion #region Case EHLO case "EHLO": myData.iState = 3; Send("250-" + Parent.ServerName + " Weavver.Net.Mail - www.weavver.com" + newline); Send("250-AUTH LOGIN" + newline); Send("250 AUTH=LOGIN" + newline); break; #endregion #region Case AUTH case "AUTH": myData.iState = 10; Send("334 VXNlcm5hbWU6" + newline); break; #endregion #region Case MAIL case "MAIL": if (myData.iState == 1 || myData.iState == 3 || myData.iState > 9) { if (pData.IndexOf("<") > 0) { myData.MailFrom = pData.Substring(pData.IndexOf("<") + 1); myData.MailFrom = myData.MailFrom.Trim().Replace(">", ""); myData.iState = 2; bool allow = Parent.CheckMAIL(this, myData.MailFrom); if (!allow) { Send("503 Permission denied.\r\n"); } else { if (myData.MailFrom == "") Send("250 2.1.5 NULL SENDER OK:" + newline); else Send("250 2.1.5 Continue:" + newline); } } else { Send("503 Invalid MAIL command, please use this format -> MAIL FROM: <you@domain> <CRLF>" + newline); } } else { Send("503 Out of sequence" + newline); } break; #endregion #region Case RCPT case "RCPT": if (myData.iState > 1 && myData.iState < 10) { if (pData.IndexOf("<") > 0) { Address address = new Address(); myData.Temp = pData.Substring(pData.IndexOf("<") + 1); address.SetAddress(myData.Temp.Replace(">", "").Trim()); ArrayList al = Parent.CheckRCPT(this, address, myData.bForward); if (al.Count == 0) { address = new Address(); address.EndPoint = AddressEndPointStatus.Bad; } for (int i = 0; i < al.Count; i++) { address = (Address) al[i]; if ( address.EndPoint == AddressEndPointStatus.Bad || address.EndPoint == AddressEndPointStatus.Blocked) { address = (Address) al[i]; if (i == al.Count && al.Count > 0) address = (Address) al[0]; break; } } switch (address.EndPoint) { case AddressEndPointStatus.Bad: case AddressEndPointStatus.Blocked: if (address.Path == "ignore" && al.Count > 1) { for (int i = 0; i < al.Count; i++) { myData.RCPT.Add(al[i]); } Send("250 2.1.5 Command good - Continue:" + newline); } else { Send("503 2.1.5 " + address.Error + newline); } break; default: for (int i = 0; i < al.Count; i++) { myData.RCPT.Add(al[i]); } Send("250 2.1.5 Command good - Continue:" + newline); break; } myData.Temp = ""; myData.iState = (myData.iState == 2 ? 3 : myData.iState); } else { Send("501 5.5.4 Invalid Address, please use this syntax: \"MAIL TO: <you@domain> <CRLF>\"" + newline); } } else { Send("503 Invalid state, please use the MAIL command first." + newline); } break; #endregion #region Case DATA case "DATA": if (myData.iState == 3 && myData.RCPT.Count > 0) { myData.iState = 4; try { if (!Directory.Exists(Parent.SmtpDirectory)) Directory.CreateDirectory(Parent.SmtpDirectory); string filepath = Parent.SmtpDirectory + "in" + Path.DirectorySeparatorChar + FileName(); myData.IncomingFile = File.Open(filepath, FileMode.Append, FileAccess.Write, FileShare.Read); string Received = "Received: from [{0}] by {1} via SMTP; {2}\r\n"; Received = String.Format(Received, myData.myEndPoint, Parent.ServerName, DateTime.Now.ToString("g")); System.Byte[] lBytes = System.Text.Encoding.ASCII.GetBytes(Received); myData.IncomingFile.Write(lBytes, 0, lBytes.Length); } catch(Exception e) { Send("500 Local error, unable to process." + newline); Parent.DebugOut("Unable to access hard drive. \r\n\r\n A possible cause may be incorrectly set NTFS permissions. \r\n\r\n" + e.Message, true); break; } Send("354 Start mail input; end with <CRLF> . <CRLF>" + newline); } else { Send("503 Command is out of sequence, please make sure you have specified recipients." + newline); } break; #endregion #region Case HELP case "HELP": Send("214 Titanium Mail http://www.titaniumsoft.net" + newline); break; #endregion #region Case QUIT case "QUIT": Send("221 2.2.0 " + Parent.ServerName + " service closing transmission channel" + newline); myData.bStayConnected = false; break; #endregion #region Case NOOP case "NOOP": Send("OK" + newline); break; #endregion #region Case RSET case "RSET": Reset(); Send("250 Command good - Continue:" + newline); break; #endregion #region Default default: if (myData.iState > 9) { HandleAuthorizationState(pData); } else { Send("503 Bad command or out of sequence." + newline); } break; #endregion } }