internal void GetConnection(ServicePoint servicePoint)
{
if (isConnected)
{
throw new InvalidOperationException(SR.GetString(SR.SmtpAlreadyConnected));
}
if (Logging.On) Logging.Associate(Logging.Web, this, servicePoint);
Debug.Assert(servicePoint != null, "servicePoint was null from SmtpTransport");
connectionPool = ConnectionPoolManager.GetConnectionPool(servicePoint, "", m_CreateConnectionCallback);
PooledStream pooledStream = connectionPool.GetConnection((object)this, null, Timeout);
while (((SmtpPooledStream)pooledStream).creds != null && ((SmtpPooledStream)pooledStream).creds != credentials) {
// destroy this connection so that a new connection can be created
// in order to use the proper credentials. Do not just close the
// connection since it's in a state where a QUIT could be sent
connectionPool.PutConnection(pooledStream, pooledStream.Owner, Timeout, false);
pooledStream = connectionPool.GetConnection((object)this, null, Timeout);
}
if (Logging.On) Logging.Associate(Logging.Web, this, pooledStream);
lock (this) {
this.pooledStream = pooledStream;
}
((SmtpPooledStream)pooledStream).creds = credentials;
responseReader = new SmtpReplyReaderFactory(pooledStream.NetworkStream);
//set connectionlease
pooledStream.UpdateLifetime();
//if the stream was already used, then we've already done the handshake
if (((SmtpPooledStream)pooledStream).previouslyUsed == true) {
isConnected = true;
return;
}
LineInfo info = responseReader.GetNextReplyReader().ReadLine();
switch (info.StatusCode)
{
case SmtpStatusCode.ServiceReady:
{
break;
}
default:
{
throw new SmtpException(info.StatusCode, info.Line, true);
}
}
try
{
extensions = EHelloCommand.Send(this, client.clientDomain);
ParseExtensions(extensions);
}
catch (SmtpException e)
{
if ((e.StatusCode != SmtpStatusCode.CommandUnrecognized)
&& (e.StatusCode != SmtpStatusCode.CommandNotImplemented)) {
throw e;
}
HelloCommand.Send(this, client.clientDomain);
//if ehello isn't supported, assume basic login
supportedAuth = SupportedAuth.Login;
}
#if !FEATURE_PAL
// Establish TLS
if (enableSsl)
{
if (!serverSupportsStartTls)
{
// Either TLS is already established or server does not support TLS
if (!(pooledStream.NetworkStream is TlsStream))
{
throw new SmtpException(SR.GetString(SR.MailServerDoesNotSupportStartTls));
}
}
StartTlsCommand.Send(this);
TlsStream TlsStream = new TlsStream(servicePoint.Host, pooledStream.NetworkStream, clientCertificates, servicePoint, client, null);
pooledStream.NetworkStream = TlsStream;
//for SMTP, the CBT should be unique
this.channelBindingToken = TlsStream.GetChannelBinding(ChannelBindingKind.Unique);
responseReader = new SmtpReplyReaderFactory(pooledStream.NetworkStream);
// According to RFC 3207: The client SHOULD send an EHLO command
// as the first command after a successful TLS negotiation.
extensions = EHelloCommand.Send(this, client.clientDomain);
ParseExtensions(extensions);
}
#endif // !FEATURE_PAL
//if no credentials were supplied, try anonymous
//servers don't appear to anounce that they support anonymous login.
if (credentials != null) {
for (int i = 0; i < authenticationModules.Length; i++)
{
//only authenticate if the auth protocol is supported - [....]
if (!AuthSupported(authenticationModules[i])) {
continue;
}
NetworkCredential credential = credentials.GetCredential(servicePoint.Host,
servicePoint.Port, authenticationModules[i].AuthenticationType);
if (credential == null)
continue;
Authorization auth = SetContextAndTryAuthenticate(authenticationModules[i], credential, null);
if (auth != null && auth.Message != null)
{
info = AuthCommand.Send(this, authenticationModules[i].AuthenticationType, auth.Message);
if (info.StatusCode == SmtpStatusCode.CommandParameterNotImplemented)
{
continue;
}
while ((int)info.StatusCode == 334)
{
auth = authenticationModules[i].Authenticate(info.Line, null, this, this.client.TargetName, this.channelBindingToken);
if (auth == null)
{
throw new SmtpException(SR.GetString(SR.SmtpAuthenticationFailed));
}
info = AuthCommand.Send(this, auth.Message);
if ((int)info.StatusCode == 235)
{
authenticationModules[i].CloseContext(this);
isConnected = true;
return;
}
}
}
}
}
isConnected = true;
}