code: async def run(self, login: LoginProtocol):
          
          self._print('%d +++| %s', bytes(socket_info.get()))
          await self._do_greeting(login)
          while True:
              resp: Response
              try:
                  cmd = await self._read_command()
              except (ConnectionError, EOFError):
                  break
              except NotParseable as exc:
                  resp = BadCommandResponse(exc)
              else:
                  try:
                      if isinstance(cmd, NoOpCommand):
                          resp = NoOpResponse(cmd.tag)
                      elif isinstance(cmd, LogoutCommand):
                          resp = Response(Condition.BYE)
                      elif isinstance(cmd, CapabilityCommand):
                          resp = CapabilitiesResponse(self.capabilities)
                      elif self._session is None:
                          if isinstance(cmd, AuthenticateCommand):
                              resp = await self._do_authenticate(login, cmd)
                          elif isinstance(cmd, StartTLSCommand):
                              resp = await self._do_starttls()
                          else:
                              resp = Response(Condition.NO, text='Bad command.')
                      else:
                          if isinstance(cmd, UnauthenticateCommand):
                              resp = await self._do_unauthenticate()
                          else:
                              assert self._session.filter_set is not None
                              state = FilterState(self._session.filter_set,
                                                  self.config)
                              resp = await state.run(cmd)
                  except Exception:
                      _log.exception('Unhandled exception')
                      resp = Response(Condition.NO, text='Server error.')
              await self._write_response(resp)
              if resp.is_bye:
                  break
          self._print('%d ---| %s', b'<disconnected>')
docs: Start the socket communication with the server greeting, and then
          enter the command/response cycle.
  
          Args:
              login: The login/authentication function.