# Path: aiosmtplib/compat.py
# async def start_tls(
#     loop: asyncio.AbstractEventLoop,
#     transport: asyncio.Transport,
#     protocol: asyncio.Protocol,
#     sslcontext: ssl.SSLContext,
#     server_side: bool = False,
#     server_hostname: Optional[str] = None,
#     ssl_handshake_timeout: Optional[Union[float, int]] = None,
# ) -> asyncio.Transport:
#     # We use hasattr here, as uvloop also supports start_tls.
#     if hasattr(loop, "start_tls"):
#         return await loop.start_tls(  # type: ignore
#             transport,
#             protocol,
#             sslcontext,
#             server_side=server_side,
#             server_hostname=server_hostname,
#             ssl_handshake_timeout=ssl_handshake_timeout,
#         )
# 
#     waiter = loop.create_future()
#     ssl_protocol = SSLProtocol(
#         loop, protocol, sslcontext, waiter, server_side, server_hostname
#     )
# 
#     # Pause early so that "ssl_protocol.data_received()" doesn't
#     # have a chance to get called before "ssl_protocol.connection_made()".
#     transport.pause_reading()
# 
#     # Use set_protocol if we can
#     if hasattr(transport, "set_protocol"):
#         transport.set_protocol(ssl_protocol)
#     else:
#         transport._protocol = ssl_protocol  # type: ignore
# 
#     conmade_cb = loop.call_soon(ssl_protocol.connection_made, transport)
#     resume_cb = loop.call_soon(transport.resume_reading)
# 
#     try:
#         await asyncio.wait_for(waiter, timeout=ssl_handshake_timeout)
#     except Exception:
#         transport.close()
#         conmade_cb.cancel()
#         resume_cb.cancel()
#         raise
# 
#     return ssl_protocol._app_transport
# 
# Path: aiosmtplib/errors.py
# class SMTPDataError(SMTPResponseException):
#     """
#     Server refused DATA content.
#     """
# 
# class SMTPReadTimeoutError(SMTPTimeoutError):
#     """
#     A timeout occurred while waiting for a response from the SMTP server.
#     """
# 
# class SMTPResponseException(SMTPException):
#     """
#     Base class for all server responses with error codes.
#     """
# 
#     def __init__(self, code: int, message: str) -> None:
#         self.code = code
#         self.message = message
#         self.args = (code, message)
# 
# class SMTPServerDisconnected(SMTPException, ConnectionError):
#     """
#     The connection was lost unexpectedly, or a command was run that requires
#     a connection.
#     """
# 
# class SMTPTimeoutError(SMTPException, TimeoutError):
#     """
#     A timeout occurred while performing a network operation.
#     """
# 
# Path: aiosmtplib/response.py
# class SMTPResponse(BaseResponse):
#     """
#     NamedTuple of server response code and server response message.
# 
#     ``code`` and ``message`` can be accessed via attributes or indexes:
# 
#         >>> response = SMTPResponse(200, "OK")
#         >>> response.message
#         'OK'
#         >>> response[0]
#         200
#         >>> response.code
#         200
# 
#     """
# 
#     __slots__ = ()
# 
#     def __repr__(self) -> str:
#         return "({self.code}, {self.message})".format(self=self)
# 
#     def __str__(self) -> str:
#         return "{self.code} {self.message}".format(self=self)
# 
# Path: aiosmtplib/status.py
# class SMTPStatus(enum.IntEnum):
#     """
#     Defines SMTP statuses for code readability.
# 
#     See also: http://www.greenend.org.uk/rjk/tech/smtpreplies.html
#     """
# 
#     invalid_response = -1
#     system_status_ok = 211
#     help_message = 214
#     ready = 220
#     closing = 221
#     auth_successful = 235
#     completed = 250
#     will_forward = 251
#     cannot_vrfy = 252
#     auth_continue = 334
#     start_input = 354
#     domain_unavailable = 421
#     mailbox_unavailable = 450
#     error_processing = 451
#     insufficient_storage = 452
#     tls_not_available = 454
#     unrecognized_command = 500
#     unrecognized_parameters = 501
#     command_not_implemented = 502
#     bad_command_sequence = 503
#     parameter_not_implemented = 504
#     domain_does_not_accept_mail = 521
#     access_denied = 530  # Sendmail specific
#     auth_failed = 535
#     mailbox_does_not_exist = 550
#     user_not_local = 551
#     storage_exceeded = 552
#     mailbox_name_invalid = 553
#     transaction_failed = 554
#     syntax_error = 555


import asyncio
import re
import ssl
from typing import Callable, Optional, cast
from .compat import start_tls
from .errors import (
    SMTPDataError,
    SMTPReadTimeoutError,
    SMTPResponseException,
    SMTPServerDisconnected,
    SMTPTimeoutError,
)
from .response import SMTPResponse
from .status import SMTPStatus
            offset += len(line)
            if len(message):
                message.extend(b"\n")
            message.extend(line[4:].strip(b" \t\r\n"))
            if line[3:4] != b"-":
                message_complete = True
                break

        if message_complete:
            response = SMTPResponse(
                code, bytes(message).decode("utf-8", "surrogateescape")
            )
            del self._buffer[:offset]
            return response
        else:
            return None

    async def read_response(self, timeout: Optional[float] = None) -> SMTPResponse:
        """
        Get a status response from the server.

        This method must be awaited once per command sent; if multiple commands
        are written to the transport without awaiting, response data will be lost.

        Returns an :class:`.response.SMTPResponse` namedtuple consisting of:
          - server response code (e.g. 250, or such, if all goes well)
          - server response string (multiline responses are converted to a
            single, multiline string).
        """
        if self._response_waiter is None:

# Path: aiosmtplib/compat.py
# async def start_tls(
#     loop: asyncio.AbstractEventLoop,
#     transport: asyncio.Transport,
#     protocol: asyncio.Protocol,
#     sslcontext: ssl.SSLContext,
#     server_side: bool = False,
#     server_hostname: Optional[str] = None,
#     ssl_handshake_timeout: Optional[Union[float, int]] = None,
# ) -> asyncio.Transport:
#     # We use hasattr here, as uvloop also supports start_tls.
#     if hasattr(loop, "start_tls"):
#         return await loop.start_tls(  # type: ignore
#             transport,
#             protocol,
#             sslcontext,
#             server_side=server_side,
#             server_hostname=server_hostname,
#             ssl_handshake_timeout=ssl_handshake_timeout,
#         )
# 
#     waiter = loop.create_future()
#     ssl_protocol = SSLProtocol(
#         loop, protocol, sslcontext, waiter, server_side, server_hostname
#     )
# 
#     # Pause early so that "ssl_protocol.data_received()" doesn't
#     # have a chance to get called before "ssl_protocol.connection_made()".
#     transport.pause_reading()
# 
#     # Use set_protocol if we can
#     if hasattr(transport, "set_protocol"):
#         transport.set_protocol(ssl_protocol)
#     else:
#         transport._protocol = ssl_protocol  # type: ignore
# 
#     conmade_cb = loop.call_soon(ssl_protocol.connection_made, transport)
#     resume_cb = loop.call_soon(transport.resume_reading)
# 
#     try:
#         await asyncio.wait_for(waiter, timeout=ssl_handshake_timeout)
#     except Exception:
#         transport.close()
#         conmade_cb.cancel()
#         resume_cb.cancel()
#         raise
# 
#     return ssl_protocol._app_transport
# 
# Path: aiosmtplib/errors.py
# class SMTPDataError(SMTPResponseException):
#     """
#     Server refused DATA content.
#     """
# 
# class SMTPReadTimeoutError(SMTPTimeoutError):
#     """
#     A timeout occurred while waiting for a response from the SMTP server.
#     """
# 
# class SMTPResponseException(SMTPException):
#     """
#     Base class for all server responses with error codes.
#     """
# 
#     def __init__(self, code: int, message: str) -> None:
#         self.code = code
#         self.message = message
#         self.args = (code, message)
# 
# class SMTPServerDisconnected(SMTPException, ConnectionError):
#     """
#     The connection was lost unexpectedly, or a command was run that requires
#     a connection.
#     """
# 
# class SMTPTimeoutError(SMTPException, TimeoutError):
#     """
#     A timeout occurred while performing a network operation.
#     """
# 
# Path: aiosmtplib/response.py
# class SMTPResponse(BaseResponse):
#     """
#     NamedTuple of server response code and server response message.
# 
#     ``code`` and ``message`` can be accessed via attributes or indexes:
# 
#         >>> response = SMTPResponse(200, "OK")
#         >>> response.message
#         'OK'
#         >>> response[0]
#         200
#         >>> response.code
#         200
# 
#     """
# 
#     __slots__ = ()
# 
#     def __repr__(self) -> str:
#         return "({self.code}, {self.message})".format(self=self)
# 
#     def __str__(self) -> str:
#         return "{self.code} {self.message}".format(self=self)
# 
# Path: aiosmtplib/status.py
# class SMTPStatus(enum.IntEnum):
#     """
#     Defines SMTP statuses for code readability.
# 
#     See also: http://www.greenend.org.uk/rjk/tech/smtpreplies.html
#     """
# 
#     invalid_response = -1
#     system_status_ok = 211
#     help_message = 214
#     ready = 220
#     closing = 221
#     auth_successful = 235
#     completed = 250
#     will_forward = 251
#     cannot_vrfy = 252
#     auth_continue = 334
#     start_input = 354
#     domain_unavailable = 421
#     mailbox_unavailable = 450
#     error_processing = 451
#     insufficient_storage = 452
#     tls_not_available = 454
#     unrecognized_command = 500
#     unrecognized_parameters = 501
#     command_not_implemented = 502
#     bad_command_sequence = 503
#     parameter_not_implemented = 504
#     domain_does_not_accept_mail = 521
#     access_denied = 530  # Sendmail specific
#     auth_failed = 535
#     mailbox_does_not_exist = 550
#     user_not_local = 551
#     storage_exceeded = 552
#     mailbox_name_invalid = 553
#     transaction_failed = 554
#     syntax_error = 555


# Path: aiosmtplib/protocol.py
import asyncio
import re
import ssl
from typing import Callable, Optional, cast
from .compat import start_tls
from .errors import (
    SMTPDataError,
    SMTPReadTimeoutError,
    SMTPResponseException,
    SMTPServerDisconnected,
    SMTPTimeoutError,
)
from .response import SMTPResponse
from .status import SMTPStatus

            offset += len(line)
            if len(message):
                message.extend(b"\n")
            message.extend(line[4:].strip(b" \t\r\n"))
            if line[3:4] != b"-":
                message_complete = True
                break

        if message_complete:
            response = SMTPResponse(
                code, bytes(message).decode("utf-8", "surrogateescape")
            )
            del self._buffer[:offset]
            return response
        else:
            return None

    async def read_response(self, timeout: Optional[float] = None) -> SMTPResponse:
        """
        Get a status response from the server.

        This method must be awaited once per command sent; if multiple commands
        are written to the transport without awaiting, response data will be lost.

        Returns an :class:`.response.SMTPResponse` namedtuple consisting of:
          - server response code (e.g. 250, or such, if all goes well)
          - server response string (multiline responses are converted to a
            single, multiline string).
        """
        if self._response_waiter is None:

            raise SMTPServerDisconnected("Connection lost")