Hacking SSL support into smtpop.dll

We use smtpop.dll in one of our applications to retrieve email from POP3 mailboxes. Today we had to connect to a mailbox over SSL, which smtpop.dll does not support.

The code to retrieve email sits behind a façade, so I expected that it would be simple to replace smtpop.dll with another library and call the new classes. But, because the façade was  tightly coupled with the interface of smtpop.dll, we needed a replacement with the same interface.

After further tests, I decided to decompile smtpop.dll, examine how it worked internally, and derive a new class from it. It turned out that two methods, Open and Quit, would need 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
    }
}

Unfortunately, the methods of class POP3Client are not virtual. But, luckily for us, some of the class members are of protected visibility and so accessible in the derived class. I rewrote the Open and Quit methods as new methods, which means that they are not polymorphic. This also forces us to replace usage of POP3Client with Pop3ClientWithSsl everywhere in the code. But, at least, we have some respite before we have to implement a cleaner solution.

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.