<?xml version="1.0" ?>
<node name="/Connection_Interface_Forwarding"
  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">

  <tp:copyright>Copyright © 2005-2010 Nokia Corporation</tp:copyright>
  <tp:copyright>Copyright © 2005-2010 Collabora Ltd.</tp:copyright>
  <tp:copyright>Copyright © 2006 INdT </tp:copyright>
  <tp:license xmlns="http://www.w3.org/1999/xhtml">
    <p>This library is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
      License as published by the Free Software Foundation; either
      version 2.1 of the License, or (at your option) any later version.</p>

    <p>This library is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Lesser General Public License for more details.</p>

    <p>You should have received a copy of the GNU Lesser General Public
      License along with this library; if not, write to the Free Software
      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      02110-1301, USA.</p>
  </tp:license>

  <interface name="org.freedesktop.Telepathy.Connection.Interface.Forwarding.DRAFT"
    tp:causes-havoc="experimental">
    <tp:added version="0.19.6">(draft version, not API-stable)</tp:added>

    <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
      <p>This connection interface is for protocols that are capable of
        signaling to remote contacts that incoming communication channels
        should be instead sent to a separate contact.  This might apply to
        things such as call forwarding, for example.</p>

      <p>In some cases, a CM may register forwarding rules with an external
        service; in those cases, it will never see the incoming channel, and
        the forwarding will happen automatically.</p>

      <p>In other cases, the CM will handle the forwarding itself.  When an
        incoming channel is detected, the status of the local user will
        determine whether or not a forwarding rule is matched.  For some
        rules, this MAY happen immediately (ie, if the user is Busy); for
        others, there MAY be a timeout (in seconds) that must expire
        before the forwarding rule is matched (the timeout is specified
        by the first element in the <tp:type>Forwarding_Rule_Entry</tp:type> list).</p>

      <p>Once a forwarding rule is matched and any necessary timeouts have
        expired, the CM can forward the incoming channel to the specified
        handle.  If for whatever reason the remote handle does not accept
        the channel AND the CM supports multiple forwarding entries AND
        any necessary timeouts have expired (specified by the next entry
        in the list), the CM can forward the incoming channel to the next
        handle in the entry list.  This continues until the list is
        exhausted, or the incoming channel is accepted.</p>

      <p>Note that the rule matches are only for the first entry in the
        in the forwarding rule list.  Once the incoming channel has been
        forwarded, the next entry in the list (assuming one exists and
        the contact that the channel has been forwarded to does not respond
        after any necessary timeouts) is used regardless of the status of
        the forwarded channel.  The initial match rule might have been
        Busy, whereas the contact that the channel has been forwarded to
        might be offline.  Even in this case, the Busy list is still
        traversed until the channel is handled (or there are no more
        forwarding entries in the list).</p>

      <p>For example, assuming the following dict for Forwarding_Rules:</p>
      <pre>
        ForwardingRules = {
          Busy: ( initial-timeout: 30, [
            (handle: 3, timeout: 15),
            (handle: 5, timeout: 20)
          ]),
          NoReply: ( initial-timeout: 15, [
            (handle: 5, timeout: 30),
            (handle: 3, timeout: 20)
          ])
        }</pre>

      <p>We can imagine a scenario where an incoming channel is detected,
        the media stream is available (ie, not Busy),
        and the local user is online.  While the CM is waiting for the local user to
        accept the channel, it looks at NoReply's first timeout value.  After 15s if
        the local user hasn't accepted, the CM forwards the channel to Handle #5.  The
        CM then waits 30s for Handle #5 to accept the channel.  If after 30s it does
        not, the CM forwards the incoming channel to Handle #3, which will have
        20s to accept the channel.</p>
    </tp:docstring>

    <tp:enum name="Forwarding_Condition" type="u">
      <tp:docstring>
        The various forwarding conditions that are supported by this interface.
        In general, the conditions should not overlap; it should be very clear
        which rule would be chosen given a CM's behavior with an incoming
        channel.  The exception to this is Unconditional,
        which will override all other rules.
      </tp:docstring>

      <tp:enumvalue value="0" suffix="Unconditional">
        <tp:docstring>
          Incoming channels should always be forwarded.  Note that setting this
          will override any other rules.  If not set, other rules will
          be checked when an incoming communication channel is detected.
        </tp:docstring>
      </tp:enumvalue>

      <tp:enumvalue value="1" suffix="Busy">
        <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
          <p>The incoming channel should be forwarded if a busy signal is
            detected.  What defines "Busy" is CM-specific (perhaps a single
            resource is already in use, or a user's status is set to Busy
            <tp:type>Connection_Presence_Type</tp:type>).</p>

          <p>If initial timeout is specified for Busy condition and call
            waiting is not supported by the service, the timeout will be
            ignored.</p>
       </tp:docstring>
      </tp:enumvalue>

      <tp:enumvalue value="2" suffix="No_Reply">
        <tp:docstring>
          The incoming channel should be forwarded if the local user doesn't
          accept it within the specified amount of time.
        </tp:docstring>
      </tp:enumvalue>

      <tp:enumvalue value="3" suffix="Not_Reachable">
        <tp:docstring>
          The incoming channel should be forwarded if the user is offline.
          This could be a manual setting (the user has chosen to set their
          presence to offline or invisible) or something specified by the
          underlying network (the user is not within range of a cell tower).
        </tp:docstring>
      </tp:enumvalue>
    </tp:enum>

    <tp:struct name="Forwarding_Rule_Entry"
        array-name="Forwarding_Rule_Entry_List">
      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
        <p>A forwarding rule entry.  These MAY be chained together
          for CMs that support chaining of forwards (in other words,
          a forwarding rule may have multiple entries; if the contact
          in the first entry doesn't respond, the incoming channel
          might be forwarded to the contact in the second entry).</p>

        <p>For CMs and protocols that don't support chaining of
          entries, only the first entry would be used.</p>
      </tp:docstring>

      <tp:member type="u" name="Timeout">
        <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
          <p>The length of time (in seconds) to wait the contact to respond
            to the forwarded channel.  This MAY be ignored by the CM if it
            isn't supported by the underlying network/protocol for the
            specific status of the remote contact (for example, a GSM call
            that is forwarded may return Not_Reachable immediately without
            waiting for the timeout value to expire).</p>

          <p>A value of 0 means the condition can match immediately. A
            value of MAX_UINT32 means that the CM's default should be
            used.</p>
        </tp:docstring>
      </tp:member>

      <tp:member type="u" tp:type="Contact_Handle" name="Handle">
        <tp:docstring>
          The contact to forward an incoming channel to. If the handle
          doesn't point to anything (e.g. points to a phone number that
          doesn't exist), the entry SHOULD be skipped.
        </tp:docstring>
      </tp:member>
    </tp:struct>

    <tp:struct name="Forwarding_Rule_Chain">
      <tp:docstring>
        A chain of forwarding rules and an initial timeout after which
        the rules are applied.
      </tp:docstring>

      <tp:member type="u" name="InitialTimeout">
        <tp:docstring>Initial timeout for the rule.</tp:docstring>
      </tp:member>

      <tp:member type="a(uu)" name="Rules" tp:type="Forwarding_Rule_Entry[]">
        <tp:docstring>The forwarding targets (an array of type
          <tp:type>Forwarding_Rule_Entry</tp:type>).
        </tp:docstring>
      </tp:member>
    </tp:struct>

    <tp:mapping name="Forwarding_Rule_Map" array-name="">
      <tp:docstring>A dictionary whose keys are forwarding conditions and
        whose values are <tp:type>Forwarding_Rule_Chain</tp:type> structs.
      </tp:docstring>

      <tp:member type="u" tp:type="Forwarding_Condition" name="Condition" />
      <tp:member type="(ua(uu))" tp:type="Forwarding_Rule_Chain"
          name="Rule_Chain" />
    </tp:mapping>

    <tp:mapping name="Supported_Forwarding_Conditions_Map" array-name="">
      <tp:docstring>A dictionary whose keys are forwarding conditions and
        whose values are maximum number of <tp:type>Forwarding_Rule_Entry</tp:type>
        for the condition.
      </tp:docstring>
      <tp:member type="u" tp:type="Forwarding_Condition" name="Condition" />
      <tp:member type="u" name="Chain_Length" />
    </tp:mapping>

    <property name="SupportedForwardingConditions" type="a{uu}" access="read"
      tp:type="Supported_Forwarding_Conditions_Map"
      tp:name-for-bindings="Supported_Forwarding_Conditions">
      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
        <p>A map of forwarding conditions supported on this connection to
          maximum number of <tp:type>Forwarding_Rule_Entry</tp:type>
          supported for the specific condition.</p>

        <tp:rationale>
          <p>When forwarding is done by the provider, different providers
            might support different chain sizes, or provider and local
            implementation chain sizes might differ.</p>
        </tp:rationale>
      </tp:docstring>
    </property>

    <property name="ForwardingRules" type="a{u(ua(uu))}" access="read"
      tp:type="Forwarding_Rule_Map" tp:name-for-bindings="Forwarding_Rules">
      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
        <p>The current forwarding rules that are enabled for this connection.
          Forwarding rules each contain an array of type
          <tp:type>Forwarding_Rule_Entry</tp:type>.</p>
      </tp:docstring>
    </property>

    <signal name="ForwardingRuleChanged"
            tp:name-for-bindings="Forwarding_Rule_Changed">
      <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
        <p>Emitted when the <tp:member-ref>ForwardingRules</tp:member-ref> property changes.</p>

        <p>By the time this is emitted, the property MUST have been updated
          with the new rules being active.  If any protocol/network
          requests must be made, they should be completed before the signal
          is emitted.</p>
      </tp:docstring>

      <arg name="Condition" type="u" tp:type="Forwarding_Condition">
        <tp:docstring>
          The condition of the forwarding rule that's been changed.
        </tp:docstring>
      </arg>

      <arg name="Timeout" type="u">
        <tp:docstring>
          The new initial timeout for the rule.
        </tp:docstring>
      </arg>

      <arg name="Forwards" type="a(uu)" tp:type="Forwarding_Rule_Entry[]">
        <tp:docstring>
          The new (and as of the emission of the signal, currently active)
          forwards.  The order is relevant; those at the lowest array index
          are used first.
        </tp:docstring>
      </arg>
    </signal>

    <method name="SetForwardingRule" tp:name-for-bindings="Set_Forwarding_Rule">
      <tp:docstring>
        Update the forwarding rules.
      </tp:docstring>

      <arg direction="in" name="Condition" type="u" tp:type="Forwarding_Condition">
        <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
          <p>The forwarding rule to override.  Note that this SHOULD not affect
            other rules; setting a rule that overrides others (such as
            Forwarding_Rule_Unconditional) will not modify other rules.  This
            means that when a client sets Forwarding_Rule_Busy and then
            temporarily sets Forwarding_Rule_Unconditional, the
            Forwarding_Rule_Busy rule will retain settings after
            Forwarding_Rule_Unconditional, has been unset.</p>

          <p>If the CM has no choice but to adjust multiple rules after a call
            to this function (ie, due to the network or protocol forcing such
            behavior), the CM MUST emit multiple <tp:member-ref>ForwardingRuleChanged</tp:member-ref>
            signals for each changed rule.  The order of the signals is
            implementation-dependent, with the only requirement that the
            last signal is for the rule that was originally requested to have
            been changed (e.g. if Unconditional automatically modifies
            Busy and NoReply, three
            separate <tp:member-ref>ForwardingRuleChanged</tp:member-ref> signals should be raised with the
            last signal being for Forwarding_Rule_Unconditional).</p>

          <p>Each forwarding condition will occur no more than once in
            the rule array.  Setting a rule will overwrite the old rule
            with the same <tp:type>Forwarding_Condition</tp:type> in its entirety.</p>
        </tp:docstring>
      </arg>

      <arg direction="in" name="Forwards" type="a(uu)" tp:type="Forwarding_Rule_Entry[]">
        <tp:docstring>
          The forwarding targets (an array of type <tp:type>Forwarding_Rule_Entry</tp:type>) to
          activate for the rule.  An empty array will effectively disable the
          rule.
        </tp:docstring>
      </arg>

      <arg direction="out" name="Old_Forwards" type="a(uu)" tp:type="Forwarding_Rule_Entry[]">
        <tp:docstring>
          The old forwarding targets (an array of type <tp:type>Forwarding_Rule_Entry</tp:type>).
          This is the list of entries that is being replaced with the call to
          <tp:member-ref>SetForwardingRule</tp:member-ref>.
        </tp:docstring>
      </arg>
      <tp:possible-errors>
        <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
        <tp:error name="org.freedesktop.Telepathy.Error.NetworkError"/>
        <tp:error name="org.freedesktop.Telepathy.Error.NotAvailable">
          <tp:docstring>
            The specified Condition is not supported by this connection,
            or the number of chained
            <tp:member-ref>SupportedForwardingConditions</tp:member-ref> should
            be checked prior to calling
            <tp:member-ref>SetForwardingRule</tp:member-ref>.
          </tp:docstring>
        </tp:error>
        <tp:error name="org.freedesktop.Telepathy.Error.InvalidHandle">
          <tp:docstring>
            A Handle that has been supplied is invalid.
          </tp:docstring>
        </tp:error>
      </tp:possible-errors>
    </method>

  </interface>
</node>
<!-- vim:set sw=2 sts=2 et ft=xml: -->
