    """M2Crypto-enhanced transport for PickleRPC

    This lets you use M2Crypto for SSL encryption.

    Based on m2xmlrpclib.py which is
    Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.

    """

    import sys
    from MiscUtils import StringIO
    from PickleRPC import Transport
    from M2Crypto import SSL, httpslib, m2urllib

    __version__ = 1 # version of M2PickleRPC

    class M2Transport(Transport):

        user_agent = "M2PickleRPC.py/%s - %s" % (__version__, Transport.user_agent)

        def __init__(self, ssl_context=None):
            if ssl_context is None:
                self.ssl_ctx = SSL.Context('sslv23')
            else:
                self.ssl_ctx = ssl_context

        def make_connection(self, host):
            _host, _port = m2urllib.splitport(host)
            if sys.version[0] == '2':
                return httpslib.HTTPS(_host, int(_port), ssl_context=self.ssl_ctx)
            elif sys.version[:3] == '1.5':
                return httpslib.HTTPS(self.ssl_ctx, _host, int(_port))
            else:
                raise RuntimeError, 'unsupported Python version'

        # @@ workarounds below are necessary because M2Crypto seems to
        # return from fileobject.read() early!  So we have to call it
        # over and over to get the full data.

        def parse_response(self, f):
            """Workaround M2Crypto issue mentioned above."""
            sio = StringIO()
            while 1:
                chunk = f.read()
                if not chunk:
                    break
                sio.write(chunk)
            sio.seek(0)
            return Transport.parse_response(self, sio)

        def parse_response_gzip(self, f):
            """Workaround M2Crypto issue mentioned above."""
            sio = StringIO()
            while 1:
                chunk = f.read()
                if not chunk:
                    break
                sio.write(chunk)
            sio.seek(0)
            return Transport.parse_response_gzip(self, sio)