Presence.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software, 2020-2024 Florian Schmaus.
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.jivesoftware.smack.packet;

  18. import java.util.List;
  19. import java.util.Locale;

  20. import org.jivesoftware.smack.XMPPConnection;
  21. import org.jivesoftware.smack.util.StringUtils;
  22. import org.jivesoftware.smack.util.XmlStringBuilder;

  23. /**
  24.  * Represents XMPP presence stanzas. Every presence stanza has a type, which is one of
  25.  * the following values:
  26.  * <ul>
  27.  *      <li>{@link Presence.Type#available available} -- (Default) indicates the user is available to
  28.  *          receive messages.
  29.  *      <li>{@link Presence.Type#unavailable unavailable} -- the user is unavailable to receive messages.
  30.  *      <li>{@link Presence.Type#subscribe subscribe} -- request subscription to recipient's presence.
  31.  *      <li>{@link Presence.Type#subscribed subscribed} -- grant subscription to sender's presence.
  32.  *      <li>{@link Presence.Type#unsubscribe unsubscribe} -- request removal of subscription to
  33.  *          sender's presence.
  34.  *      <li>{@link Presence.Type#unsubscribed unsubscribed} -- grant removal of subscription to
  35.  *          sender's presence.
  36.  *      <li>{@link Presence.Type#error error} -- the presence stanza contains an error message.
  37.  * </ul><p>
  38.  *
  39.  * A number of attributes are optional:
  40.  * <ul>
  41.  *      <li>Status -- free-form text describing a user's presence (i.e., gone to lunch).
  42.  *      <li>Priority -- non-negative numerical priority of a sender's resource. The
  43.  *          highest resource priority is the default recipient of packets not addressed
  44.  *          to a particular resource.
  45.  *      <li>Mode -- one of five presence modes: {@link Mode#available available} (the default),
  46.  *          {@link Mode#chat chat}, {@link Mode#away away}, {@link Mode#xa xa} (extended away), and
  47.  *          {@link Mode#dnd dnd} (do not disturb).
  48.  * </ul><p>
  49.  *
  50.  * Presence stanzas are used for two purposes. First, to notify the server of
  51.  * the user's current presence status. Second, they are used to subscribe and
  52.  * unsubscribe users from the roster.
  53.  *
  54.  * @author Matt Tucker
  55.  */
  56. public final class Presence extends MessageOrPresence<PresenceBuilder>
  57.                 implements PresenceView {

  58.     public static final String ELEMENT = "presence";

  59.     private Type type = Type.available;
  60.     private String status = null;

  61.     /**
  62.      * The priority of the presence. It is <code>null</code> to indicate that the original
  63.      * presence stanza did not had an explicit priority set. In which case the priority defaults to 0.
  64.      *
  65.      * @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3.</a>
  66.      */
  67.     private Byte priority;

  68.     private Mode mode = null;

  69.     Presence(PresenceBuilder presenceBuilder) {
  70.         super(presenceBuilder);
  71.         type = presenceBuilder.type;
  72.         status = presenceBuilder.status;
  73.         priority = presenceBuilder.priority;
  74.         mode = presenceBuilder.mode;
  75.     }

  76.     /**
  77.      * Copy constructor.
  78.      * <p>
  79.      * This does not perform a deep clone, as extension elements are shared between the new and old
  80.      * instance.
  81.      * </p>
  82.      *
  83.      * @param other TODO javadoc me please
  84.      */
  85.     public Presence(Presence other) {
  86.         super(other);
  87.         this.type = other.type;
  88.         this.status = other.status;
  89.         this.priority = other.priority;
  90.         this.mode = other.mode;
  91.     }

  92.     /**
  93.      * Returns true if the {@link Type presence type} is available (online) and
  94.      * false if the user is unavailable (offline), or if this is a presence packet
  95.      * involved in a subscription operation. This is a convenience method
  96.      * equivalent to <code>getType() == Presence.Type.available</code>. Note that even
  97.      * when the user is available, their presence mode may be {@link Mode#away away},
  98.      * {@link Mode#xa extended away} or {@link Mode#dnd do not disturb}. Use
  99.      * {@link #isAway()} to determine if the user is away.
  100.      *
  101.      * @return true if the presence type is available.
  102.      */
  103.     public boolean isAvailable() {
  104.         return type == Type.available;
  105.     }

  106.     /**
  107.      * Returns true if the presence type is {@link Type#available available} and the presence
  108.      * mode is {@link Mode#away away}, {@link Mode#xa extended away}, or
  109.      * {@link Mode#dnd do not disturb}. False will be returned when the type or mode
  110.      * is any other value, including when the presence type is unavailable (offline).
  111.      * This is a convenience method equivalent to
  112.      * <code>type == Type.available &amp;&amp; (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd)</code>.
  113.      *
  114.      * @return true if the presence type is available and the presence mode is away, xa, or dnd.
  115.      */
  116.     public boolean isAway() {
  117.         return type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd);
  118.     }

  119.     @Override
  120.     public Type getType() {
  121.         return type;
  122.     }

  123.     @Override
  124.     public String getStatus() {
  125.         return status;
  126.     }

  127.     @Override
  128.     public int getPriority() {
  129.         return getPriorityByte();
  130.     }

  131.     @Override
  132.     public byte getPriorityByte() {
  133.         if (priority == null) {
  134.             return 0;
  135.         }
  136.         return priority;
  137.     }

  138.     /**
  139.      * Sets the priority of the presence. The valid range is -128 through 127.
  140.      *
  141.      * @param priority the priority of the presence.
  142.      * @see <a href="https://tools.ietf.org/html/rfc6121#section-4.7.2.3">RFC 6121 § 4.7.2.3. Priority Element</a>
  143.      * @deprecated use {@link PresenceBuilder} or {@link org.jivesoftware.smack.XMPPConnection#getStanzaFactory} instead.
  144.      */
  145.     @Deprecated
  146.     // TODO: Remove in Smack 4.6.
  147.     public void setPriority(byte priority) {
  148.         this.priority = priority;
  149.     }

  150.     @Override
  151.     public Mode getMode() {
  152.         if (mode == null) {
  153.             return Mode.available;
  154.         }
  155.         return mode;
  156.     }

  157.     @Override
  158.     public String getElementName() {
  159.         return ELEMENT;
  160.     }

  161.     @Override
  162.     public PresenceBuilder asBuilder() {
  163.         return StanzaBuilder.buildPresenceFrom(this, getStanzaId());
  164.     }

  165.     @Override
  166.     public PresenceBuilder asBuilder(String id) {
  167.         return StanzaBuilder.buildPresenceFrom(this, id);
  168.     }

  169.     @Override
  170.     public PresenceBuilder asBuilder(XMPPConnection connection) {
  171.         return connection.getStanzaFactory().buildPresenceStanzaFrom(this);
  172.     }

  173.     @Override
  174.     public String toString() {
  175.         StringBuilder sb = new StringBuilder();
  176.         sb.append("Presence Stanza [");
  177.         logCommonAttributes(sb);
  178.         sb.append("type=").append(type).append(',');
  179.         if (mode != null) {
  180.             sb.append("mode=").append(mode).append(',');
  181.         }
  182.         if (!StringUtils.isNullOrEmpty(status)) {
  183.             sb.append("status=").append(status).append(',');
  184.         }
  185.         if (priority != null) {
  186.             sb.append("prio=").append(priority).append(',');
  187.         }
  188.         sb.append(']');
  189.         return sb.toString();
  190.     }

  191.     @Override
  192.     public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  193.         XmlStringBuilder buf = new XmlStringBuilder(this, enclosingNamespace);
  194.         addCommonAttributes(buf);
  195.         if (type != Type.available) {
  196.             buf.attribute("type", type);
  197.         }

  198.         List<XmlElement> extensions = getExtensions();
  199.         if (status == null
  200.                         && priority == null
  201.                         && (mode == null || mode == Mode.available)
  202.                         && extensions.isEmpty()
  203.                         && getError() == null) {
  204.             return buf.closeEmptyElement();
  205.         }

  206.         buf.rightAngleBracket();

  207.         buf.optElement("status", status);
  208.         buf.optElement("priority", priority);
  209.         if (mode != null && mode != Mode.available) {
  210.             buf.element("show", mode);
  211.         }

  212.         buf.append(extensions);

  213.         // Add the error sub-packet, if there is one.
  214.         appendErrorIfExists(buf);

  215.         buf.closeElement(ELEMENT);

  216.         return buf;
  217.     }

  218.     /**
  219.      * An enum to represent the presence type. Note that presence type is often confused
  220.      * with presence mode. Generally, if a user is signed in to a server, they have a presence
  221.      * type of {@link #available available}, even if the mode is {@link Mode#away away},
  222.      * {@link Mode#dnd dnd}, etc. The presence type is only {@link #unavailable unavailable} when
  223.      * the user is signing out of the server.
  224.      */
  225.     public enum Type {

  226.        /**
  227.         * The user is available to receive messages (default).
  228.         */
  229.         available,

  230.         /**
  231.          * The user is unavailable to receive messages.
  232.          */
  233.         unavailable,

  234.         /**
  235.          * Request subscription to recipient's presence.
  236.          */
  237.         subscribe,

  238.         /**
  239.          * Grant subscription to sender's presence.
  240.          */
  241.         subscribed,

  242.         /**
  243.          * Request removal of subscription to sender's presence.
  244.          */
  245.         unsubscribe,

  246.         /**
  247.          * Grant removal of subscription to sender's presence.
  248.          */
  249.         unsubscribed,

  250.         /**
  251.          * The presence stanza contains an error message.
  252.          */
  253.         error,

  254.         /**
  255.          * A presence probe as defined in section 4.3 of RFC 6121.
  256.          */
  257.         probe,
  258.         ;

  259.         /**
  260.          * Converts a String into the corresponding types. Valid String values that can be converted
  261.          * to types are: "available", "unavailable", "subscribe", "subscribed", "unsubscribe",
  262.          * "unsubscribed" and "error".
  263.          *
  264.          * @param string the String value to covert.
  265.          * @return the corresponding Type.
  266.          * @throws IllegalArgumentException when not able to parse the string parameter
  267.          * @throws NullPointerException if the string is null
  268.          */
  269.         public static Type fromString(String string) {
  270.             return Type.valueOf(string.toLowerCase(Locale.US));
  271.         }
  272.     }

  273.     /**
  274.      * An enum to represent the presence mode.
  275.      */
  276.     public enum Mode {

  277.         /**
  278.          * Free to chat.
  279.          */
  280.         chat,

  281.         /**
  282.          * Available (the default).
  283.          */
  284.         available,

  285.         /**
  286.          * Away.
  287.          */
  288.         away,

  289.         /**
  290.          * Away for an extended period of time.
  291.          */
  292.         xa,

  293.         /**
  294.          * Do not disturb.
  295.          */
  296.         dnd;

  297.         /**
  298.          * Converts a String into the corresponding types. Valid String values that can be converted
  299.          * to types are: "chat", "available", "away", "xa", and "dnd".
  300.          *
  301.          * @param string the String value to covert.
  302.          * @return the corresponding Type.
  303.          * @throws IllegalArgumentException when not able to parse the string parameter
  304.          * @throws NullPointerException if the string is null
  305.          */
  306.         public static Mode fromString(String string) {
  307.             return Mode.valueOf(string.toLowerCase(Locale.US));
  308.         }
  309.     }
  310. }