using System.Collections;
using System.Net.Sockets;
using System.Security.Permissions;
+using System.Reflection;
namespace System.Web.Mail {
private string server;
private TcpClient tcpConnection;
private SmtpStream smtp;
-
- //Initialise the variables and connect
+ private string username;
+ private string password;
+ private int port = 25;
+ private bool usessl = false;
+ private short authenticate = 1;
+
+ //Initialise the variables and connect
public SmtpClient( string server ) {
this.server = server;
// make the actual connection
// and HELO handshaking
private void Connect() {
- tcpConnection = new TcpClient( server , 25 );
+ tcpConnection = new TcpClient( server , port );
- Stream stream = tcpConnection.GetStream();
+ NetworkStream stream = tcpConnection.GetStream();
smtp = new SmtpStream( stream );
-
- // read the server greeting
- smtp.ReadResponse();
- smtp.CheckForStatusCode( 220 );
-
- // write the HELO command to the server
- smtp.WriteHelo( Dns.GetHostName() );
+ }
+ private void ChangeToSSLSocket( ) {
+#if TARGET_JVM
+ java.lang.Class c = vmw.common.TypeUtils.ToClass( smtp.Stream );
+ java.lang.reflect.Method m = c.getMethod("ChangeToSSLSocket", null);
+ m.invoke(smtp.Stream, new object[]{});
+#else
+ // Load Mono.Security.dll
+ Assembly a;
+ try {
+ a = Assembly.Load("Consts.AssemblyMono_Security");
+ }
+ catch(System.IO.FileNotFoundException) {
+ throw new SmtpException( "Cannot load Mono.Security.dll" );
+ }
+ Type tSslClientStream = a.GetType("Mono.Security.Protocol.Tls.SslClientStream");
+ object[] consArgs = new object[4];
+ consArgs[0] = smtp.Stream;
+ consArgs[1] = server;
+ consArgs[2] = true;
+ Type tSecurityProtocolType = a.GetType("Mono.Security.Protocol.Tls.SecurityProtocolType");
+ int nSsl3Val = (int) Enum.Parse(tSecurityProtocolType, "Ssl3");
+ int nTlsVal = (int) Enum.Parse(tSecurityProtocolType, "Tls");
+ consArgs[3] = Enum.ToObject(tSecurityProtocolType, nSsl3Val | nTlsVal);
+
+ object objSslClientStream =
+ Activator.CreateInstance(tSslClientStream, consArgs);
+
+ if (objSslClientStream != null)
+ smtp = new SmtpStream( (Stream)objSslClientStream );
+#endif
+ }
+
+ private void ReadFields(MailMessageWrapper msg)
+ {
+ string tmp;
+ username = msg.Fields.Data["http://schemas.microsoft.com/cdo/configuration/sendusername"];
+ password = msg.Fields.Data["http://schemas.microsoft.com/cdo/configuration/sendpassword"];
+ tmp = msg.Fields.Data["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"];
+ if (tmp != null)
+ authenticate = short.Parse(tmp);
+ tmp = msg.Fields.Data["http://schemas.microsoft.com/cdo/configuration/smtpusessl"];
+ if (tmp != null)
+ usessl = bool.Parse(tmp);
+ tmp = msg.Fields.Data["http://schemas.microsoft.com/cdo/configuration/smtpserverport"];
+ if (tmp != null)
+ port = int.Parse(tmp);
+ }
+
+ private void StartSend(MailMessageWrapper msg)
+ {
+ ReadFields(msg);
+
+ // read the server greeting
+ smtp.ReadResponse();
+ smtp.CheckForStatusCode( 220 );
+
+ if (usessl || (username != null && password != null && authenticate != 1))
+ {
+ smtp.WriteEhlo( Dns.GetHostName() );
+
+ if (usessl) {
+ bool isSSL = smtp.WriteStartTLS();
+ if (isSSL)
+ ChangeToSSLSocket();
+ }
+
+ if (username != null && password != null && authenticate != 1)
+ {
+ smtp.WriteAuthLogin();
+ if (smtp.LastResponse.StatusCode == 334)
+ {
+ smtp.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(username)));
+ smtp.ReadResponse();
+ smtp.CheckForStatusCode(334);
+ smtp.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(password)));
+ smtp.ReadResponse();
+ smtp.CheckForStatusCode(235);
+ }
+ }
+ }
+ else
+ {
+ smtp.WriteHelo( Dns.GetHostName() );
+ }
}
public void Send( MailMessageWrapper msg ) {
if( msg.To.Count < 1 ) throw new SmtpException( "Atleast one recipient must be set." );
}
-
+ StartSend (msg);
// start with a reset incase old data
// is present at the server in this session
smtp.WriteRset();
if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] != null)
msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate");
if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/sendusername"] != null)
- msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/sendusername");\r
- if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/sendpassword"] != null)\r
+ msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/sendusername");
+ if (msg.Fields.Data ["http://schemas.microsoft.com/cdo/configuration/sendpassword"] != null)
msg.Fields.Data.Remove ("http://schemas.microsoft.com/cdo/configuration/sendpassword");
partHeader.Data.Add (msg.Fields.Data);
#endif
}
+ public void WriteAuthLogin()
+ {
+ command = "AUTH LOGIN";
+ WriteLine( command );
+ ReadResponse();
+ }
+
+ public bool WriteStartTLS( )
+ {
+ command = "STARTTLS";
+ WriteLine( command );
+ ReadResponse();
+ return LastResponse.StatusCode == 220;
+
+ }
+
+ public void WriteEhlo( string hostName )
+ {
+ command = "EHLO " + hostName;
+ WriteLine( command );
+ ReadResponse();
+ CheckForStatusCode( 250 );
+
+ }
+
public void WriteHelo( string hostName ) {
command = "HELO " + hostName;
WriteLine( command );
// read a line from the server
public void ReadResponse( ) {
- string line = null;
-
- byte[] buffer = new byte[ 4096 ];
-
- int readLength = stream.Read( buffer , 0 , buffer.Length );
-
- if( readLength > 0 ) {
-
- line = encoding.GetString( buffer , 0 , readLength );
- line = line.TrimEnd( new Char[] { '\r' , '\n' , ' ' } );
+ byte[] buffer = new byte [512];
+ int position = 0;
+ bool lastLine = false;
+
+ do {
+ int readLength = stream.Read (buffer , position , buffer.Length - position);
+ if (readLength > 0) {
+ int available = position + readLength - 1;
+ if (available > 4 && (buffer [available] == '\n' || buffer [available] == '\r'))
+ for (int index = available - 3; ; index--) {
+ if (index < 0 || buffer [index] == '\n' || buffer [index] == '\r') {
+ lastLine = buffer [index + 4] == ' ';
+ break;
+ }
+ }
+
+ // move position
+ position += readLength;
+
+ // check if buffer is full
+ if (position == buffer.Length) {
+ byte [] newBuffer = new byte [buffer.Length * 2];
+ Array.Copy (buffer, 0, newBuffer, 0, buffer.Length);
+ buffer = newBuffer;
+ }
+ }
+ } while(!lastLine);
+
+ string line = encoding.GetString (buffer , 0 , position - 1);
- }
-
// parse the line to the lastResponse object
- lastResponse = SmtpResponse.Parse( line );
+ lastResponse = SmtpResponse.Parse (line);
#if DEBUG
DebugPrint( line );