:orphan:

:py:mod:`slidge.core.gateway`
=============================

.. py:module:: slidge.core.gateway


Submodules
----------
.. toctree::
   :titlesonly:
   :maxdepth: 1

   base/index.rst
   delivery_receipt/index.rst


Package Contents
----------------

Classes
~~~~~~~

.. autoapisummary::

   slidge.core.gateway.BaseGateway




.. py:class:: BaseGateway




   The gateway component, handling registrations and un-registrations.

   On slidge launch, a singleton is instantiated, and it will be made available
   to public classes such :class:`.LegacyContact` or :class:`.BaseSession` as the
   ``.xmpp`` attribute.

   Must be subclassed by a legacy module to set up various aspects of the XMPP
   component behaviour, such as its display name or welcome message, via
   class attributes :attr:`.COMPONENT_NAME` :attr:`.WELCOME_MESSAGE`.

   Abstract methods related to the registration process must be overriden
   for a functional :term:`Legacy Module`:

   - :meth:`.validate`
   - :meth:`.validate_two_factor_code`
   - :meth:`.get_qr_text`
   - :meth:`.confirm_qr`

   NB: Not all of these must be overridden, it depends on the
   :attr:`REGISTRATION_TYPE`.

   The other methods, such as :meth:`.send_text` or :meth:`.react` are the same
   as those of :class:`.LegacyContact` and :class:`.LegacyParticipant`, because
   the component itself is also a "messaging actor", ie, an :term:`XMPP Entity`.
   For these methods, you need to specify the JID of the recipient with the
   `mto` parameter.

   Since it inherits from :class:`slixmpp.componentxmpp.ComponentXMPP`,you also
   have a hand on low-level XMPP interactions via slixmpp methods, e.g.:

   .. code-block:: python

       self.send_presence(
           pfrom="somebody@component.example.com",
           pto="someonwelse@anotherexample.com",
       )

   However, you should not need to do so often since the classes of the plugin
   API provides higher level abstractions around most commonly needed use-cases, such
   as sending messages, or displaying a custom status.


   .. py:attribute:: COMPONENT_NAME
      :type: str

      Name of the component, as seen in service discovery by XMPP clients


   .. py:attribute:: COMPONENT_TYPE
      :type: str
      :value: ''

      Type of the gateway, should follow https://xmpp.org/registrar/disco-categories.html


   .. py:attribute:: COMPONENT_AVATAR
      :type: Optional[slidge.util.types.AvatarType]

      Path, bytes or URL used by the component as an avatar.


   .. py:attribute:: REGISTRATION_FIELDS
      :type: Collection[slidge.command.base.FormField]

      Iterable of fields presented to the gateway user when registering using :xep:`0077`
      `extended <https://xmpp.org/extensions/xep-0077.html#extensibility>`_ by :xep:`0004`.


   .. py:attribute:: REGISTRATION_INSTRUCTIONS
      :type: str
      :value: 'Enter your credentials'

      The text presented to a user that wants to register (or modify) their legacy account
      configuration.


   .. py:attribute:: REGISTRATION_TYPE
      :type: slidge.command.register.RegistrationType

      This attribute determines how users register to the gateway, ie, how they
      login to the :term:`legacy service <Legacy Service>`.
      The credentials are then stored persistently, so this process should happen
      once per user (unless they unregister).

      The registration process always start with a basic data form (:xep:`0004`)
      presented to the user.
      But the legacy login flow might require something more sophisticated, see
      :class:`.RegistrationType` for more details.


   .. py:attribute:: ROSTER_GROUP
      :type: str
      :value: 'slidge'

      Name of the group assigned to a :class:`.LegacyContact` automagically
      added to the :term:`User`'s roster with :meth:`.LegacyContact.add_to_roster`.


   .. py:attribute:: WELCOME_MESSAGE
      :value: "Thank you for registering. Type 'help' to list the available commands, or just start messaging away!"

      A welcome message displayed to users on registration.
      This is useful notably for clients that don't consider component JIDs as a
      valid recipient in their UI, yet still open a functional chat window on
      incoming messages from components.


   .. py:attribute:: SEARCH_FIELDS
      :type: Sequence[slidge.command.base.FormField]

      Fields used for searching items via the component, through :xep:`0055` (jabber search).
      A common use case is to allow users to search for legacy contacts by something else than
      their usernames, eg their phone number.

      Plugins should implement search by overriding :meth:`.BaseSession.search`
      (restricted to registered users).

      If there is only one field, it can also be used via the ``jabber:iq:gateway`` protocol
      described in :xep:`0100`. Limitation: this only works if the search request returns
      one result item, and if this item has a 'jid' var.


   .. py:attribute:: SEARCH_TITLE
      :type: str
      :value: 'Search for legacy contacts'

      Title of the search form.


   .. py:attribute:: SEARCH_INSTRUCTIONS
      :type: str
      :value: ''

      Instructions of the search form.


   .. py:attribute:: MARK_ALL_MESSAGES
      :value: False

      Set this to True for :term:`legacy networks <Legacy Network>` that expects
      read marks for *all* messages and not just the latest one that was read
      (as most XMPP clients will only send a read mark for the latest msg).


   .. py:attribute:: PROPER_RECEIPTS
      :value: False

      Set this to True if the legacy service provides a real equivalent of message delivery receipts
      (:xep:`0184`), meaning that there is an event thrown when the actual device of a contact receives
      a message. Make sure to call Contact.received() adequately if this is set to True.


   .. py:method:: validate(user_jid, registration_form)
      :abstractmethod:
      :async:

      Validate a user's initial registration form.

      Should raise the appropriate :class:`slixmpp.exceptions.XMPPError`
      if the registration does not allow to continue the registration process.

      If :py:attr:`REGISTRATION_TYPE` is a
      :attr:`.RegistrationType.SINGLE_STEP_FORM`,
      this method should raise something if it wasn't possible to successfully
      log in to the legacy service with the registration form content.

      It is also used for other types of :py:attr:`REGISTRATION_TYPE` too, since
      the first step is always a form. If :attr:`.REGISTRATION_FIELDS` is an
      empty list (ie, it declares no :class:`.FormField`), the "form" is
      effectively a confirmation dialog displaying
      :attr:`.REGISTRATION_INSTRUCTIONS`.

      :param user_jid: JID of the user that has just registered
      :param registration_form: A dict where keys are the :attr:`.FormField.var` attributes
       of the :attr:`.BaseGateway.REGISTRATION_FIELDS` iterable


   .. py:method:: validate_two_factor_code(user, code)
      :abstractmethod:
      :async:

      Called when the user enters their 2FA code.

      Should raise the appropriate :class:`slixmpp.exceptions.XMPPError`
      if the login fails, and return successfully otherwise.

      Only used when :attr:`REGISTRATION_TYPE` is
      :attr:`.RegistrationType.TWO_FACTOR_CODE`.

      :param user: The :class:`.GatewayUser` whose registration is pending
          Use their :attr:`.GatewayUser.bare_jid` and/or
          :attr:`.registration_form` attributes to get what you need.
      :param code: The code they entered, either via "chatbot" message or
          adhoc command


   .. py:method:: get_qr_text(user)
      :abstractmethod:
      :async:

      This is where slidge gets the QR code content for the QR-based
      registration process. It will turn it into a QR code image and send it
      to the not-yet-fully-registered :class:`.GatewayUser`.

      Only used in when :attr:`BaseGateway.REGISTRATION_TYPE` is
      :attr:`.RegistrationType.QRCODE`.

      :param user: The :class:`.GatewayUser` whose registration is pending
          Use their :attr:`.GatewayUser.bare_jid` and/or
          :attr:`.registration_form` attributes to get what you need.


   .. py:method:: confirm_qr(user_bare_jid, exception = None)
      :async:

      This method is meant to be called to finalize QR code-based registration
      flows, once the legacy service confirms the QR flashing.

      Only used in when :attr:`BaseGateway.REGISTRATION_TYPE` is
      :attr:`.RegistrationType.QRCODE`.

      :param user_bare_jid: The bare JID of the almost-registered
          :class:`GatewayUser` instance
      :param exception: Optionally, an XMPPError to be raised to **not** confirm
          QR code flashing.


   .. py:method:: unregister(user)
      :async:

      Optionally override this if you need to clean additional
      stuff after a user has been removed from the permanent user_store.

      By default, this just calls :meth:`BaseSession.logout`.

      :param user:


   .. py:method:: input(jid, text=None, mtype = 'chat', **msg_kwargs)
      :async:

      Request arbitrary user input using a simple chat message, and await the result.

      You shouldn't need to call this directly bust instead use
      :meth:`.BaseSession.input` to directly target a user.

      :param jid: The JID we want input from
      :param text: A prompt to display for the user
      :param mtype: Message type
      :return: The user's reply


   .. py:method:: send_qr(text, **msg_kwargs)
      :async:

      Sends a QR Code to a JID

      You shouldn't need to call directly bust instead use
      :meth:`.BaseSession.send_qr` to directly target a user.

      :param text: The text that will be converted to a QR Code
      :param msg_kwargs: Optional additional arguments to pass to
          :meth:`.BaseGateway.send_file`, such as the recipient of the QR,
          code


   .. py:method:: invite_to(muc, reason = None, password = None, **send_kwargs)

      Send an invitation to join a group (:xep:`0249`) from this :term:`XMPP Entity`.

      :param muc: the muc the user is invited to
      :param reason: a text explaining why the user should join this muc
      :param password: maybe this will make sense later? not sure
      :param send_kwargs: additional kwargs to be passed to _send()
          (internal use by slidge)


   .. py:method:: active(**kwargs)

      Send an "active" chat state (:xep:`0085`) from this
      :term:`XMPP Entity`.


   .. py:method:: composing(**kwargs)

      Send a "composing" (ie "typing notification") chat state (:xep:`0085`)
      from this :term:`XMPP Entity`.


   .. py:method:: paused(**kwargs)

      Send a "paused" (ie "typing paused notification") chat state
      (:xep:`0085`) from this :term:`XMPP Entity`.


   .. py:method:: inactive(**kwargs)

      Send an "inactive" (ie "contact has not interacted with the chat session
      interface for an intermediate period of time") chat state (:xep:`0085`)
      from this :term:`XMPP Entity`.


   .. py:method:: gone(**kwargs)

      Send a "gone" (ie "contact has not interacted with the chat session interface,
      system, or device for a relatively long period of time") chat state
      (:xep:`0085`) from this :term:`XMPP Entity`.


   .. py:method:: ack(legacy_msg_id, **kwargs)

      Send an "acknowledged" message marker (:xep:`0333`) from this :term:`XMPP Entity`.

      :param legacy_msg_id: The message this marker refers to


   .. py:method:: received(legacy_msg_id, **kwargs)

      Send a "received" message marker (:xep:`0333`) from this :term:`XMPP Entity`.
      If called on a :class:`LegacyContact`, also send a delivery receipt
      marker (:xep:`0184`).

      :param legacy_msg_id: The message this marker refers to


   .. py:method:: displayed(legacy_msg_id, **kwargs)

      Send a "displayed" message marker (:xep:`0333`) from this :term:`XMPP Entity`.

      :param legacy_msg_id: The message this marker refers to


   .. py:method:: send_text(body, legacy_msg_id = None, *, when = None, reply_to = None, thread = None, hints = None, carbon=False, archive_only=False, correction=False, correction_event_id = None, link_previews = None, **send_kwargs)

      Send a text message from this :term:`XMPP Entity`.

      :param body: Content of the message
      :param legacy_msg_id: If you want to be able to transport read markers from the gateway
          user to the legacy network, specify this
      :param when: when the message was sent, for a "delay" tag (:xep:`0203`)
      :param reply_to: Quote another message (:xep:`0461`)
      :param hints:
      :param thread:
      :param carbon: (only used if called on a :class:`LegacyContact`)
          Set this to ``True`` if this is actually a message sent **to** the
          :class:`LegacyContact` by the :term:`User`.
          Use this to synchronize outgoing history for legacy official apps.
      :param correction: whether this message is a correction or not
      :param correction_event_id: in the case where an ID is associated with the legacy
          'correction event', specify it here to use it on the XMPP side. If not specified,
          a random ID will be used.
      :param link_previews: A little of sender (or server, or gateway)-generated
          previews of URLs linked in the body.
      :param archive_only: (only in groups) Do not send this message to user,
          but store it in the archive. Meant to be used during ``MUC.backfill()``


   .. py:method:: correct(legacy_msg_id, new_text, *, when = None, reply_to = None, thread = None, hints = None, carbon=False, archive_only=False, correction_event_id = None, link_previews = None, **send_kwargs)

      Modify a message that was previously sent by this :term:`XMPP Entity`.

      Uses last message correction (:xep:`0308`)

      :param new_text: New content of the message
      :param legacy_msg_id: The legacy message ID of the message to correct
      :param when: when the message was sent, for a "delay" tag (:xep:`0203`)
      :param reply_to: Quote another message (:xep:`0461`)
      :param hints:
      :param thread:
      :param carbon: (only in 1:1) Reflect a message sent to this ``Contact`` by the user.
          Use this to synchronize outgoing history for legacy official apps.
      :param archive_only: (only in groups) Do not send this message to user,
          but store it in the archive. Meant to be used during ``MUC.backfill()``
      :param correction_event_id: in the case where an ID is associated with the legacy
          'correction event', specify it here to use it on the XMPP side. If not specified,
          a random ID will be used.
      :param link_previews: A little of sender (or server, or gateway)-generated
          previews of URLs linked in the body.


   .. py:method:: react(legacy_msg_id, emojis = (), thread = None, **kwargs)

      Send a reaction (:xep:`0444`) from this :term:`XMPP Entity`.

      :param legacy_msg_id: The message which the reaction refers to.
      :param emojis: An iterable of emojis used as reactions
      :param thread:


   .. py:method:: retract(legacy_msg_id, thread = None, **kwargs)

      Send a message retraction (:XEP:`0424`) from this :term:`XMPP Entity`.

      :param legacy_msg_id: Legacy ID of the message to delete
      :param thread:


   .. py:method:: send_file(file_path = None, legacy_msg_id = None, *, data_stream = None, data = None, file_url = None, file_name = None, content_type = None, reply_to = None, when = None, caption = None, legacy_file_id = None, thread = None, **kwargs)
      :async:

      Send a single file from this :term:`XMPP Entity`.

      :param file_path: Path to the attachment
      :param data_stream: Alternatively, a stream of bytes (such as a File object)
      :param data: Alternatively, a bytes object
      :param file_url: Alternatively, a URL
      :param file_name: How the file should be named.
      :param content_type: MIME type, inferred from filename if not given
      :param legacy_msg_id: If you want to be able to transport read markers from the gateway
          user to the legacy network, specify this
      :param reply_to: Quote another message (:xep:`0461`)
      :param when: when the file was sent, for a "delay" tag (:xep:`0203`)
      :param caption: an optional text that is linked to the file
      :param legacy_file_id: A unique identifier for the file on the legacy network.
           Plugins should try their best to provide it, to avoid duplicates.
      :param thread:



