Skip to content
Snippets Groups Projects
specification.rst 90.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • suitably namespaced for each application and reduces the risk of clashes.
    
    State events
    
    State events can be sent by ``PUT`` ing to
    |/rooms/<room_id>/state/<event_type>/<state_key>|_.  These events will be
    overwritten if ``<room id>``, ``<event type>`` and ``<state key>`` all match.
    If the state event has no ``state_key``, it can be omitted from the path. These
    requests **cannot use transaction IDs** like other ``PUT`` paths because they
    cannot be differentiated from the ``state_key``. Furthermore, ``POST`` is
    unsupported on state paths. Valid requests look like::
    
      PUT /rooms/!roomid:domain/state/m.example.event
      { "key" : "without a state key" }
    
      PUT /rooms/!roomid:domain/state/m.another.example.event/foo
      { "key" : "with 'foo' as the state key" }
    
      POST /rooms/!roomid:domain/state/m.example.event/
      { "key" : "cannot use POST here" }
    
      PUT /rooms/!roomid:domain/state/m.another.example.event/foo/11
      { "key" : "txnIds are not supported" }
    
    Care should be taken to avoid setting the wrong ``state key``::
    
      PUT /rooms/!roomid:domain/state/m.another.example.event/11
      { "key" : "with '11' as the state key, but was probably intended to be a txnId" }
    
    The ``state_key`` is often used to store state about individual users, by using
    the user ID as the ``state_key`` value. For example::
    
      PUT /rooms/!roomid:domain/state/m.favorite.animal.event/%40my_user%3Adomain.com
      { "animal" : "cat", "reason": "fluffy" }
    
    In some cases, there may be no need for a ``state_key``, so it can be omitted::
    
      PUT /rooms/!roomid:domain/state/m.room.bgd.color
      { "color": "red", "hex": "#ff0000" }
    
    See `Room Events`_ for the ``m.`` event specification.
    
    Non-state events
    ----------------
    Non-state events can be sent by sending a request to
    |/rooms/<room_id>/send/<event_type>|_.  These requests *can* use transaction
    IDs and ``PUT``/``POST`` methods. Non-state events allow access to historical
    events and pagination, making it best suited for sending messages.  For
    example::
    
      POST /rooms/!roomid:domain/send/m.custom.example.message
      { "text": "Hello world!" }
    
      PUT /rooms/!roomid:domain/send/m.custom.example.message/11
      { "text": "Goodbye world!" }
    
    See `Room Events`_ for the ``m.`` event specification.
    
    Syncing rooms
    -------------
    .. NOTE::
      This section is a work in progress.
    
    When a client logs in, they may have a list of rooms which they have already
    joined. These rooms may also have a list of events associated with them. The
    purpose of 'syncing' is to present the current room and event information in a
    convenient, compact manner. The events returned are not limited to room events;
    presence events will also be returned. There are two APIs provided:
    
     - |initialSync|_ : A global sync which will present room and event information
       for all rooms the user has joined.
    
     - |/rooms/<room_id>/initialSync|_ : A sync scoped to a single room. Presents
       room and event information for this room only.
    
      - TODO: JSON response format for both types
      - TODO: when would you use global? when would you use scoped?
    
    Getting events for a room
    -------------------------
    There are several APIs provided to ``GET`` events for a room:
    
    ``/rooms/<room id>/state/<event type>/<state key>``
      Description:
        Get the state event identified.
      Response format:
        A JSON object representing the state event **content**.
      Example:
        ``/rooms/!room:domain.com/state/m.room.name`` returns ``{ "name": "Room name" }``
    
    |/rooms/<room_id>/state|_
      Description:
        Get all state events for a room.
      Response format:
        ``[ { state event }, { state event }, ... ]``
      Example:
    
    |/rooms/<room_id>/members|_
      Description:
        Get all ``m.room.member`` state events.
      Response format:
        ``{ "start": "<token>", "end": "<token>", "chunk": [ { m.room.member event }, ... ] }``
      Example:
    
    |/rooms/<room_id>/messages|_
      Description:
        Get all ``m.room.message`` and ``m.room.member`` events. This API supports
        pagination using ``from`` and ``to`` query parameters, coupled with the
        ``start`` and ``end`` tokens from an |initialSync|_ API.
      Response format:
        ``{ "start": "<token>", "end": "<token>" }``
      Example:
    
        Get all relevant events for a room. This includes state events, paginated
        non-state events and presence events.
    
    Redactions
    ----------
    
    Since events are extensible it is possible for malicious users and/or servers
    to add keys that are, for example offensive or illegal. Since some events
    cannot be simply deleted, e.g. membership events, we instead 'redact' events.
    This involves removing all keys from an event that are not required by the
    protocol. This stripped down event is thereafter returned anytime a client or
    remote server requests it.
    
    Events that have been redacted include a ``redacted_because`` key whose value
    is the event that caused it to be redacted, which may include a reason.
    
    Redacting an event cannot be undone, allowing server owners to delete the
    offending content from the databases.
    
    Currently, only room admins can redact events by sending a ``m.room.redaction``
    
    event, but server admins also need to be able to redact events by a similar
    mechanism.
    
    Upon receipt of a redaction event, the server should strip off any keys not in
    the following list:
    
     - ``event_id``
     - ``type``
     - ``room_id``
     - ``user_id``
     - ``state_key``
     - ``prev_state``
     - ``content``
    
    The content object should also be stripped of all keys, unless it is one of
    one of the following event types:
    
     - ``m.room.member`` allows key ``membership``
     - ``m.room.create`` allows key ``creator``
     - ``m.room.join_rules`` allows key ``join_rule``
     - ``m.room.power_levels`` allows keys that are user ids or ``default``
     - ``m.room.add_state_level`` allows key ``level``
     - ``m.room.send_event_level`` allows key ``level``
     - ``m.room.ops_levels`` allows keys ``kick_level``, ``ban_level``
       and ``redact_level``
     - ``m.room.aliases`` allows key ``aliases``
    
    The redaction event should be added under the key ``redacted_because``.
    
    
    When a client receives a redaction event it should change the redacted event
    in the same way a server does.
    
    
    Room Events
    ===========
    .. NOTE::
      This section is a work in progress.
    
    This specification outlines several standard event types, all of which are
    prefixed with ``m.``
    
    ``m.room.name``
      Summary:
        Set the human-readable name for the room.
      Type: 
        State event
      JSON format:
        ``{ "name" : "string" }``
      Example:
        ``{ "name" : "My Room" }``
      Description:
        A room has an opaque room ID which is not human-friendly to read. A room
        alias is human-friendly, but not all rooms have room aliases. The room name
        is a human-friendly string designed to be displayed to the end-user. The
        room name is not *unique*, as multiple rooms can have the same room name
        set. The room name can also be set when creating a room using |createRoom|_
        with the ``name`` key.
    
    ``m.room.topic``
      Summary:
        Set a topic for the room.
      Type: 
        State event
      JSON format:
        ``{ "topic" : "string" }``
      Example:
        ``{ "topic" : "Welcome to the real world." }``
      Description:
        A topic is a short message detailing what is currently being discussed in
        the room.  It can also be used as a way to display extra information about
        the room, which may not be suitable for the room name. The room topic can
        also be set when creating a room using |createRoom|_ with the ``topic``
        key.
    
    ``m.room.member``
      Summary:
        The current membership state of a user in the room.
      Type: 
        State event
      JSON format:
        ``{ "membership" : "enum[ invite|join|leave|ban ]" }``
      Example:
        ``{ "membership" : "join" }``
      Description:
        Adjusts the membership state for a user in a room. It is preferable to use
        the membership APIs (``/rooms/<room id>/invite`` etc) when performing
        membership actions rather than adjusting the state directly as there are a
        restricted set of valid transformations. For example, user A cannot force
        user B to join a room, and trying to force this state change directly will
        fail. See the `Rooms`_ section for how to use the membership APIs.
    
    ``m.room.create``
      Summary:
        The first event in the room.
      Type: 
        State event
      JSON format:
        ``{ "creator": "string"}``
      Example:
        ``{ "creator": "@user:example.com" }``
      Description:
        This is the first event in a room and cannot be changed. It acts as the 
        root of all other events.
    
    ``m.room.join_rules``
      Summary:
        Descripes how/if people are allowed to join.
      Type: 
        State event
      JSON format:
        ``{ "join_rule": "enum [ public|knock|invite|private ]" }``
      Example:
        ``{ "join_rule": "public" }``
      Description:
    
       
    ``m.room.power_levels``
      Summary:
        Defines the power levels of users in the room.
      Type: 
        State event
      JSON format:
        ``{ "<user_id>": <int>, ..., "default": <int>}``
      Example:
        ``{ "@user:example.com": 5, "@user2:example.com": 10, "default": 0 }`` 
      Description:
        If a user is in the list, then they have the associated power level. 
        Otherwise they have the default level. If not ``default`` key is supplied,
        it is assumed to be 0.
    
    ``m.room.add_state_level``
      Summary:
        Defines the minimum power level a user needs to add state.
      Type: 
        State event
      JSON format:
        ``{ "level": <int> }``
      Example:
        ``{ "level": 5 }``
      Description:
        To add a new piece of state to the room a user must have the given power 
        level. This does not apply to updating current state, which is goverened
        by the ``required_power_level`` event key.
        
    ``m.room.send_event_level``
      Summary:
        Defines the minimum power level a user needs to send an event.
      Type: 
        State event
      JSON format:
        ``{ "level": <int> }``
      Example:
        ``{ "level": 0 }``
      Description:
        To send a new event into the room a user must have at least this power 
        level. This allows ops to make the room read only by increasing this level,
        or muting individual users by lowering their power level below this
        threshold.
    
    ``m.room.ops_levels``
      Summary:
        Defines the minimum power levels that a user must have before they can 
        kick and/or ban other users.
      Type: 
        State event
      JSON format:
    
        ``{ "ban_level": <int>, "kick_level": <int>, "redact_level": <int> }``
    
      Example:
        ``{ "ban_level": 5, "kick_level": 5 }``
      Description:
        This defines who can ban and/or kick people in the room. Most of the time
        ``ban_level`` will be greater than or equal to ``kick_level`` since 
        banning is more severe than kicking.
    
    ``m.room.aliases``
      Summary:
        These state events are used to inform the room about what room aliases it
        has.
      Type:
        State event
      JSON format:
        ``{ "aliases": ["string", ...] }``
      Example:
        ``{ "aliases": ["#foo:example.com"] }``
      Description:
        A server `may` inform the room that it has added or removed an alias for
        the room. This is purely for informational purposes and may become stale.
        Clients `should` check that the room alias is still valid before using it.
        The ``state_key`` of the event is the homeserver which owns the room alias.
    
    ``m.room.message``
      Summary:
        A message.
      Type: 
        Non-state event
      JSON format:
        ``{ "msgtype": "string" }``
      Example:
        ``{ "msgtype": "m.text", "body": "Testing" }``
      Description:
        This event is used when sending messages in a room. Messages are not
        limited to be text.  The ``msgtype`` key outlines the type of message, e.g.
        text, audio, image, video, etc.  Whilst not required, the ``body`` key
        SHOULD be used with every kind of ``msgtype`` as a fallback mechanism when
        a client cannot render the message. For more information on the types of
        messages which can be sent, see `m.room.message msgtypes`_.
    
    ``m.room.message.feedback``
      Summary:
        A receipt for a message.
      Type: 
        Non-state event
      JSON format:
        ``{ "type": "enum [ delivered|read ]", "target_event_id": "string" }``
      Example:
        ``{ "type": "delivered", "target_event_id": "e3b2icys" }``
      Description:
        Feedback events are events sent to acknowledge a message in some way. There
        are two supported acknowledgements: ``delivered`` (sent when the event has
        been received) and ``read`` (sent when the event has been observed by the
        end-user). The ``target_event_id`` should reference the ``m.room.message``
        event being acknowledged. 
    
    ``m.room.redaction``
      Summary:
        Indicates a previous event has been redacted.
      Type:
        Non-state event
      JSON format:
        ``{ "reason": "string" }``
      Description:
    
        Events can be redacted by either room or server admins. Redacting an event
        means that all keys not required by the protocol are stripped off, allowing
        admins to remove offensive or illegal content that may have been attached
        to any event. This cannot be undone, allowing server owners to physically
        delete the offending data.  There is also a concept of a moderator hiding a
        non-state event, which can be undone, but cannot be applied to state
        events.
        The event that has been redacted is specified in the ``redacts`` event
        level key.
    
    Erik Johnston's avatar
    Erik Johnston committed
    
    .. TODO-spec
       How a client should handle unknown message types.
    
    
    Each ``m.room.message`` MUST have a ``msgtype`` key which identifies the type
    of message being sent. Each type has their own required and optional keys, as
    outlined below:
    
    ``m.text``
      Required keys:
        - ``body`` : "string" - The body of the message.
      Optional keys:
        None.
      Example:
        ``{ "msgtype": "m.text", "body": "I am a fish" }``
    
    ``m.emote``
      Required keys:
        - ``body`` : "string" - The emote action to perform.
      Optional keys:
        None.
      Example:
        ``{ "msgtype": "m.emote", "body": "tries to come up with a witty explanation" }``
    
    ``m.image``
      Required keys:
        - ``url`` : "string" - The URL to the image.
      Optional keys:
        - ``info`` : "string" - info : JSON object (ImageInfo) - The image info for
          image referred to in ``url``.
        - ``thumbnail_url`` : "string" - The URL to the thumbnail.
        - ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
          image referred to in ``thumbnail_url``.
        - ``body`` : "string" - The alt text of the image, or some kind of content
          description for accessibility e.g. "image attachment".
    
      ImageInfo: 
        Information about an image::
        
          { 
            "size" : integer (size of image in bytes),
            "w" : integer (width of image in pixels),
            "h" : integer (height of image in pixels),
            "mimetype" : "string (e.g. image/jpeg)",
          }
    
    ``m.audio``
      Required keys:
        - ``url`` : "string" - The URL to the audio.
      Optional keys:
        - ``info`` : JSON object (AudioInfo) - The audio info for the audio
          referred to in ``url``.
        - ``body`` : "string" - A description of the audio e.g. "Bee Gees - Stayin'
          Alive", or some kind of content description for accessibility e.g.
          "audio attachment".
      AudioInfo: 
        Information about a piece of audio::
    
          {
            "mimetype" : "string (e.g. audio/aac)",
            "size" : integer (size of audio in bytes),
            "duration" : integer (duration of audio in milliseconds),
          }
    
    ``m.video``
      Required keys:
        - ``url`` : "string" - The URL to the video.
      Optional keys:
        - ``info`` : JSON object (VideoInfo) - The video info for the video
          referred to in ``url``.
        - ``body`` : "string" - A description of the video e.g. "Gangnam style", or
          some kind of content description for accessibility e.g. "video
          attachment".
    
          {
            "mimetype" : "string (e.g. video/mp4)",
            "size" : integer (size of video in bytes),
            "duration" : integer (duration of video in milliseconds),
            "w" : integer (width of video in pixels),
            "h" : integer (height of video in pixels),
            "thumbnail_url" : "string (URL to image)",
            "thumbanil_info" : JSON object (ImageInfo)
          }
    
    ``m.location``
      Required keys:
        - ``geo_uri`` : "string" - The geo URI representing the location.
      Optional keys:
        - ``thumbnail_url`` : "string" - The URL to a thumnail of the location
          being represented.
        - ``thumbnail_info`` : JSON object (ImageInfo) - The image info for the
          image referred to in ``thumbnail_url``.
        - ``body`` : "string" - A description of the location e.g. "Big Ben,
          London, UK", or some kind of content description for accessibility e.g.
          "location attachment".
    
    The following keys can be attached to any ``m.room.message``:
    
      Optional keys:
        - ``sender_ts`` : integer - A timestamp (ms resolution) representing the
          wall-clock time when the message was sent from the client.
    
    Presence
    ========
    .. NOTE::
      This section is a work in progress.
    
    Each user has the concept of presence information. This encodes the
    "availability" of that user, suitable for display on other user's clients. This
    is transmitted as an ``m.presence`` event and is one of the few events which
    are sent *outside the context of a room*. The basic piece of presence
    information is represented by the ``presence`` key, which is an enum of one of
    the following:
    
      - ``online`` : The default state when the user is connected to an event
        stream.
      - ``unavailable`` : The user is not reachable at this time.
      - ``offline`` : The user is not connected to an event stream.
      - ``free_for_chat`` : The user is generally willing to receive messages
        moreso than default.
    
      - ``hidden`` : Behaves as offline, but allows the user to see the client
        state anyway and generally interact with client features. (Not yet
        implemented in synapse).
    
    This basic ``presence`` field applies to the user as a whole, regardless of how
    many client devices they have connected. The home server should synchronise
    this status choice among multiple devices to ensure the user gets a consistent
    experience.
    
    In addition, the server maintains a timestamp of the last time it saw an active
    action from the user; either sending a message to a room, or changing presence
    state from a lower to a higher level of availability (thus: changing state from
    ``unavailable`` to ``online`` will count as an action for being active, whereas
    in the other direction will not). This timestamp is presented via a key called
    ``last_active_ago``, which gives the relative number of miliseconds since the
    message is generated/emitted, that the user was last seen active.
    
    Home servers can also use the user's choice of presence state as a signal for
    how to handle new private one-to-one chat message requests. For example, it
    might decide:
    
      - ``free_for_chat`` : accept anything
      - ``online`` : accept from anyone in my addres book list
      - ``busy`` : accept from anyone in this "important people" group in my
        address book list
    
    
    Presence List
    -------------
    Each user's home server stores a "presence list" for that user. This stores a
    list of other user IDs the user has chosen to add to it. To be added to this
    list, the user being added must receive permission from the list owner. Once
    granted, both user's HS(es) store this information. Since such subscriptions
    are likely to be bidirectional, HSes may wish to automatically accept requests
    when a reverse subscription already exists.
    
    As a convenience, presence lists should support the ability to collect users
    into groups, which could allow things like inviting the entire group to a new
    ("ad-hoc") chat room, or easy interaction with the profile information ACL
    implementation of the HS.
    
    
    Presence and Permissions
    ------------------------
    For a viewing user to be allowed to see the presence information of a target
    user, either:
    
     - The target user has allowed the viewing user to add them to their presence
       list, or
     - The two users share at least one room in common
    
    In the latter case, this allows for clients to display some minimal sense of
    presence information in a user list for a room.
    
    
    Client API
    ----------
    The client API for presence is on the following set of REST calls.
    
    Fetching basic status::
    
      GET $PREFIX/presence/:user_id/status
    
      Returned content: JSON object containing the following keys:
        presence: "offline"|"unavailable"|"online"|"free_for_chat"
        status_msg: (optional) string of freeform text
        last_active_ago: miliseconds since the last activity by the user
    
    Setting basic status::
    
      PUT $PREFIX/presence/:user_id/status
    
      Content: JSON object containing the following keys:
        presence and status_msg: as above
    
    When setting the status, the activity time is updated to reflect that activity;
    the client does not need to specify the ``last_active_ago`` field.
    
    Fetching the presence list::
    
      GET $PREFIX/presence/list
    
      Returned content: JSON array containing objects; each object containing the
        following keys:
        user_id: observed user ID
        presence: "offline"|"unavailable"|"online"|"free_for_chat"
        status_msg: (optional) string of freeform text
        last_active_ago: miliseconds since the last activity by the user
    
    Maintaining the presence list::
    
      POST $PREFIX/presence/list
    
      Content: JSON object containing either or both of the following keys:
        invite: JSON array of strings giving user IDs to send invites to
        drop: JSON array of strings giving user IDs to remove from the list
    
    .. TODO-spec
      - Define how users receive presence invites, and how they accept/decline them
    
    Server API
    ----------
    The server API for presence is based entirely on exchange of the following
    EDUs. There are no PDUs or Federation Queries involved.
    
    Performing a presence update and poll subscription request::
    
      EDU type: m.presence
    
      Content keys:
        push: (optional): list of push operations.
          Each should be an object with the following keys:
            user_id: string containing a User ID
            presence: "offline"|"unavailable"|"online"|"free_for_chat"
            status_msg: (optional) string of freeform text
            last_active_ago: miliseconds since the last activity by the user
    
        poll: (optional): list of strings giving User IDs
    
        unpoll: (optional): list of strings giving User IDs
    
    The presence of this combined message is two-fold: it informs the recipient
    server of the current status of one or more users on the sending server (by the
    ``push`` key), and it maintains the list of users on the recipient server that
    the sending server is interested in receiving updates for, by adding (by the
    ``poll`` key) or removing them (by the ``unpoll`` key). The ``poll`` and
    ``unpoll`` lists apply *changes* to the implied list of users; any existing IDs
    that the server sent as ``poll`` operations in a previous message are not
    removed until explicitly requested by a later ``unpoll``.
    
    On receipt of a message containing a non-empty ``poll`` list, the receiving
    server should immediately send the sending server a presence update EDU of its
    own, containing in a ``push`` list the current state of every user that was in
    the orginal EDU's ``poll`` list.
    
    Sending a presence invite::
    
      EDU type: m.presence_invite
    
      Content keys:
        observed_user: string giving the User ID of the user whose presence is
          requested (i.e. the recipient of the invite)
        observer_user: string giving the User ID of the user who is requesting to
          observe the presence (i.e. the sender of the invite)
    
    Accepting a presence invite::
    
      EDU type: m.presence_accept
    
      Content keys - as for m.presence_invite
    
    Rejecting a presence invite::
    
      EDU type: m.presence_deny
    
      Content keys - as for m.presence_invite
    
    
    .. TODO-doc
      - Explain the timing-based roundtrip reduction mechanism for presence
        messages
      - Explain the zero-byte presence inference logic
      See also: docs/client-server/model/presence
    
    
    Voice over IP
    =============
    Matrix can also be used to set up VoIP calls. This is part of the core
    specification, although is still in a very early stage. Voice (and video) over
    Matrix is based on the WebRTC standards.
    
    Call events are sent to a room, like any other event. This means that clients
    must only send call events to rooms with exactly two participants as currently
    the WebRTC standard is based around two-party communication.
    
    Events
    ------
    ``m.call.invite``
    This event is sent by the caller when they wish to establish a call.
    
      Required keys:
        - ``call_id`` : "string" - A unique identifier for the call
        - ``offer`` : "offer object" - The session description
        - ``version`` : "integer" - The version of the VoIP specification this
          message adheres to. This specification is version 0.
        - ``lifetime`` : "integer" - The time in milliseconds that the invite is
          valid for. Once the invite age exceeds this value, clients should discard
          it. They should also no longer show the call as awaiting an answer in the
          UI.
          
      Optional keys:
        None.
      Example:
        ``{ "version" : 0, "call_id": "12345", "offer": { "type" : "offer", "sdp" : "v=0\r\no=- 6584580628695956864 2 IN IP4 127.0.0.1[...]" } }``
    
    ``Offer Object``
      Required keys:
        - ``type`` : "string" - The type of session description, in this case
          'offer'
        - ``sdp`` : "string" - The SDP text of the session description
    
    ``m.call.candidates``
    This event is sent by callers after sending an invite and by the callee after
    answering.  Its purpose is to give the other party additional ICE candidates to
    try using to communicate.
    
      Required keys:
        - ``call_id`` : "string" - The ID of the call this event relates to
        - ``version`` : "integer" - The version of the VoIP specification this
          messages adheres to. his specification is version 0.
        - ``candidates`` : "array of candidate objects" - Array of object
          describing the candidates.
    
      Required Keys:
        - ``sdpMid`` : "string" - The SDP media type this candidate is intended
          for.
        - ``sdpMLineIndex`` : "integer" - The index of the SDP 'm' line this
          candidate is intended for
        - ``candidate`` : "string" - The SDP 'a' line of the candidate
    
      Required keys:
        - ``call_id`` : "string" - The ID of the call this event relates to
        - ``version`` : "integer" - The version of the VoIP specification this
          messages
        - ``answer`` : "answer object" - Object giving the SDK answer
    
      Required keys:
        - ``type`` : "string" - The type of session description. 'answer' in this
          case.
        - ``sdp`` : "string" - The SDP text of the session description
    
    ``m.call.hangup``
    Sent by either party to signal their termination of the call. This can be sent
    either once the call has has been established or before to abort the call.
    
      Required keys:
        - ``call_id`` : "string" - The ID of the call this event relates to
        - ``version`` : "integer" - The version of the VoIP specification this
          messages
    
    Message Exchange
    ----------------
    A call is set up with messages exchanged as follows:
    
       Caller                   Callee
     m.call.invite ----------->
     m.call.candidate -------->
     [more candidates events]
                             User answers call
                      <------ m.call.answer
                   [...]
                      <------ m.call.hangup
                      
    Or a rejected call:
    
       Caller                   Callee
     m.call.invite ----------->
     m.call.candidate -------->
     [more candidates events]
                            User rejects call
                     <------- m.call.hangup
    
    Calls are negotiated according to the WebRTC specification.
    
    Glare
    -----
    This specification aims to address the problem of two users calling each other
    at roughly the same time and their invites crossing on the wire. It is a far
    better experience for the users if their calls are connected if it is clear
    that their intention is to set up a call with one another.
    
    In Matrix, calls are to rooms rather than users (even if those rooms may only
    contain one other user) so we consider calls which are to the same room.
    
    The rules for dealing with such a situation are as follows:
    
     - If an invite to a room is received whilst the client is preparing to send an
       invite to the same room, the client should cancel its outgoing call and
       instead automatically accept the incoming call on behalf of the user.
     - If an invite to a room is received after the client has sent an invite to
       the same room and is waiting for a response, the client should perform a
       lexicographical comparison of the call IDs of the two calls and use the
       lesser of the two calls, aborting the greater. If the incoming call is the
       lesser, the client should accept this call on behalf of the user.
    
    The call setup should appear seamless to the user as if they had simply placed
    a call and the other party had accepted. Thusly, any media stream that had been
    setup for use on a call should be transferred and used for the call that
    replaces it.
     
    
    Profiles
    ========
    .. NOTE::
      This section is a work in progress.
    
    .. TODO-spec
    
    Internally within Matrix users are referred to by their user ID, which is
    typically a compact unique identifier. Profiles grant users the ability to see
    human-readable names for other users that are in some way meaningful to them.
    Additionally, profiles can publish additional information, such as the user's
    age or location.
    
    A Profile consists of a display name, an avatar picture, and a set of other
    metadata fields that the user may wish to publish (email address, phone
    numbers, website URLs, etc...). This specification puts no requirements on the
    
    display name other than it being a valid unicode string. Avatar images are not
    stored directly; instead the home server stores an ``http``-scheme URL where
    clients may fetch it from.
    
    Client API
    ----------
    The client API for profile management consists of the following REST calls.
    
    Fetching a user account displayname::
    
      GET $PREFIX/profile/:user_id/displayname
    
      Returned content: JSON object containing the following keys:
        displayname: string of freeform text
    
    This call may be used to fetch the user's own displayname or to query the name
    of other users; either locally or on remote systems hosted on other home
    servers.
    
    Setting a new displayname::
    
      PUT $PREFIX/profile/:user_id/displayname
    
      Content: JSON object containing the following keys:
        displayname: string of freeform text
    
    Fetching a user account avatar URL::
    
      GET $PREFIX/profile/:user_id/avatar_url
    
      Returned content: JSON object containing the following keys:
        avatar_url: string containing an http-scheme URL
    
    As with displayname, this call may be used to fetch either the user's own, or
    other users' avatar URL.
    
    Setting a new avatar URL::
    
      PUT $PREFIX/profile/:user_id/avatar_url
    
      Content: JSON object containing the following keys:
        avatar_url: string containing an http-scheme URL
    
    Fetching combined account profile information::
    
      GET $PREFIX/profile/:user_id
    
      Returned content: JSON object containing the following keys:
        displayname: string of freeform text
        avatar_url: string containing an http-scheme URL
    
    At the current time, this API simply returns the displayname and avatar URL
    information, though it is intended to return more fields about the user's
    profile once they are defined. Client implementations should take care not to
    expect that these are the only two keys returned as future versions of this
    specification may yield more keys here.
    
    Server API
    ----------
    The server API for profiles is based entirely on the following Federation
    Queries. There are no additional EDU or PDU types involved, other than the
    implicit ``m.presence`` and ``m.room.member`` events (see section below).
    
    Querying profile information::
    
      Query type: profile
    
      Arguments:
        user_id: the ID of the user whose profile to return
        field: (optional) string giving a field name
    
      Returns: JSON object containing the following keys:
        displayname: string of freeform text
        avatar_url: string containing an http-scheme URL
    
    If the query contains the optional ``field`` key, it should give the name of a
    result field. If such is present, then the result should contain only a field
    of that name, with no others present. If not, the result should contain as much
    of the user's profile as the home server has available and can make public.
    
    Events on Change of Profile Information
    ---------------------------------------
    Because the profile displayname and avatar information are likely to be used in
    many places of a client's display, changes to these fields cause an automatic
    propagation event to occur, informing likely-interested parties of the new
    values. This change is conveyed using two separate mechanisms:
    
     - a ``m.room.member`` event is sent to every room the user is a member of,
       to update the ``displayname`` and ``avatar_url``.
     - a presence status update is sent, again containing the new values of the
       ``displayname`` and ``avatar_url`` keys, in addition to the required
       ``presence`` key containing the current presence state of the user.
    
    Both of these should be done automatically by the home server when a user
    successfully changes their displayname or avatar URL fields.
    
    Additionally, when home servers emit room membership events for their own
    users, they should include the displayname and avatar URL fields in these
    events so that clients already have these details to hand, and do not have to
    perform extra roundtrips to query it.
    
    .. NOTE::
      This section is a work in progress.
    
      - 3PIDs and identity server, functions
    
    Federation is the term used to describe how to communicate between Matrix home
    
    servers. Federation is a mechanism by which two home servers can exchange
    Matrix event messages, both as a real-time push of current events, and as a
    historic fetching mechanism to synchronise past history for clients to view. It
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
    uses HTTPS connections between each pair of servers involved as the underlying
    
    transport. Messages are exchanged between servers in real-time by active
    pushing from each server's HTTP client into the server of the other. Queries to
    fetch historic data for the purpose of back-filling scrollback buffers and the
    like can also be performed. Currently routing of messages between homeservers
    is full mesh (like email) - however, fan-out refinements to this design are
    currently under consideration.
    
    
    There are three main kinds of communication that occur between home servers:
    
    
       These are single request/response interactions between a given pair of
    
    Matthew Hodgson's avatar
    Matthew Hodgson committed
       servers, initiated by one side sending an HTTPS GET request to obtain some
    
       information, and responded by the other. They are not persisted and contain
    
       no long-term significant history. They simply request a snapshot state at
       the instant the query is made.
    
       These are notifications of events that are pushed from one home server to
    
       another. They are not persisted and contain no long-term significant
       history, nor does the receiving home server have to reply to them.
    
       These are notifications of events that are broadcast from one home server to
       any others that are interested in the same "context" (namely, a Room ID).
       They are persisted to long-term storage and form the record of history for
       that context.
    
    
    EDUs and PDUs are further wrapped in an envelope called a Transaction, which is
    transferred from the origin to the destination home server using an HTTP PUT
    request.
    
    .. WARNING::
      This section may be misleading or inaccurate.
    
    
    The transfer of EDUs and PDUs between home servers is performed by an exchange
    
    of Transaction messages, which are encoded as JSON objects, passed over an HTTP
    PUT request. A Transaction is meaningful only to the pair of home servers that
    
    exchanged it; they are not globally-meaningful.
    
    Each transaction has:
     - An opaque transaction ID.
    
     - A timestamp (UNIX epoch time in milliseconds) generated by its origin
       server.
    
     - An origin and destination server name.
     - A list of "previous IDs".
    
     - A list of PDUs and EDUs - the actual message payload that the Transaction
       carries.