We use smtpop.dll in one application to retrieve email from a POP3 mailbox. Today we had to connect to a mailbox over SSL, which smtpop.dll does not support.
Our code to retrieve email is abstracted behind a façade class, so I expected to simply substitute a new library for smtpop.dll and to call new methods. However, the tight coupling of the façade to the interface of smtpop.dll meant that we needed the replacement to also expose the exact same interface.
After trying several things, I resigned to create a new class with the code from the decompilation of smtpop.dll. Fortunately, only two methods, Open
and Quit
, had to be changed.
namespace ClassLibrary4
{
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using SmtPop;
public class Pop3ClientWithSsl : POP3Client
{
#region Fields
private SslStream sslStream;
#endregion
#region Constructors and Destructors
public Pop3ClientWithSsl()
{
this.UseSsl = true;
}
#endregion
#region Public Properties
public bool UseSsl { get; set; }
#endregion
#region Public Methods and Operators
public new int Open(string hostname, int port, string username, string password)
{
if (this.UseSsl)
{
return this.OpenWithSsl(hostname, port, username, password);
}
return base.Open(hostname, port, username, password);
}
public new string Quit()
{
try
{
return base.Quit();
}
finally
{
this.m_streamReader.Close();
this.m_streamWriter.Close();
if (this.UseSsl)
{
this.sslStream.Close();
}
}
}
#endregion
#region Methods
private int OpenWithSsl(string hostname, int port, string username, string password)
{
this.m_host = hostname;
this.m_port = port;
this.m_user = username;
this.m_tcpClient = new TcpClient(hostname, port);
this.m_netStream = this.m_tcpClient.GetStream();
this.sslStream = new SslStream(this.m_netStream, false);
this.sslStream.AuthenticateAsClient(hostname);
this.m_streamReader = new StreamReader(this.sslStream);
this.m_streamWriter = new StreamWriter(this.sslStream) { AutoFlush = true };
string welcome = this.m_streamReader.ReadLine();
if (welcome != null && welcome.StartsWith(+OK))
{
return this.SendLogin(username, password);
}
this.m_error = welcome;
return -1;
}
#endregion
}
}
The methods of class POP3Client
were not virtual, but some of the class members were in protected
scope and were accessible in the new class. I rewrote the Open
and Quit
methods as new
methods, which made them no longer polymorphic, thus forcing us to replace calls to POP3Client
with calls to Pop3ClientWithSsl
everywhere in the code.