MUCUser.java

  1. /**
  2.  *
  3.  * Copyright 2003-2007 Jive Software.
  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.smackx.muc.packet;

  18. import java.util.HashMap;
  19. import java.util.HashSet;
  20. import java.util.Map;
  21. import java.util.Set;

  22. import javax.xml.namespace.QName;

  23. import org.jivesoftware.smack.packet.ExtensionElement;
  24. import org.jivesoftware.smack.packet.NamedElement;
  25. import org.jivesoftware.smack.packet.Stanza;
  26. import org.jivesoftware.smack.util.XmlStringBuilder;

  27. import org.jxmpp.jid.EntityBareJid;
  28. import org.jxmpp.jid.EntityFullJid;
  29. import org.jxmpp.jid.EntityJid;

  30. /**
  31.  * Represents extended presence information about roles, affiliations, full JIDs,
  32.  * or status codes scoped by the 'http://jabber.org/protocol/muc#user' namespace.
  33.  *
  34.  * @author Gaston Dombiak
  35.  */
  36. public class MUCUser implements ExtensionElement {

  37.     public static final String ELEMENT = "x";
  38.     public static final String NAMESPACE = MUCInitialPresence.NAMESPACE + "#user";
  39.     public static final QName QNAME = new QName(NAMESPACE, ELEMENT);

  40.     private final Set<Status> statusCodes = new HashSet<>(4);

  41.     private Invite invite;
  42.     private Decline decline;
  43.     private MUCItem item;
  44.     private String password;
  45.     private Destroy destroy;

  46.     @Override
  47.     public String getElementName() {
  48.         return ELEMENT;
  49.     }

  50.     @Override
  51.     public String getNamespace() {
  52.         return NAMESPACE;
  53.     }

  54.     @Override
  55.     public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  56.         XmlStringBuilder xml = new XmlStringBuilder(this);
  57.         xml.rightAngleBracket();
  58.         xml.optElement(getInvite());
  59.         xml.optElement(getDecline());
  60.         xml.optElement(getItem());
  61.         xml.optElement("password", getPassword());
  62.         xml.append(statusCodes);
  63.         xml.optElement(getDestroy());
  64.         xml.closeElement(this);
  65.         return xml;
  66.     }

  67.     /**
  68.      * Returns the invitation for another user to a room. The sender of the invitation
  69.      * must be an occupant of the room. The invitation will be sent to the room which in turn
  70.      * will forward the invitation to the invitee.
  71.      *
  72.      * @return an invitation for another user to a room.
  73.      */
  74.     public Invite getInvite() {
  75.         return invite;
  76.     }

  77.     /**
  78.      * Returns the rejection to an invitation from another user to a room. The rejection will be
  79.      * sent to the room which in turn will forward the refusal to the inviting user.
  80.      *
  81.      * @return a rejection to an invitation from another user to a room.
  82.      */
  83.     public Decline getDecline() {
  84.         return decline;
  85.     }

  86.     /**
  87.      * Returns the item child that holds information about roles, affiliation, jids and nicks.
  88.      *
  89.      * @return an item child that holds information about roles, affiliation, jids and nicks.
  90.      */
  91.     public MUCItem getItem() {
  92.         return item;
  93.     }

  94.     /**
  95.      * Returns the password to use to enter Password-Protected Room. A Password-Protected Room is
  96.      * a room that a user cannot enter without first providing the correct password.
  97.      *
  98.      * @return the password to use to enter Password-Protected Room.
  99.      */
  100.     public String getPassword() {
  101.         return password;
  102.     }

  103.     /**
  104.      * Returns a set of status which holds the status code that assist in presenting notification messages.
  105.      *
  106.      * @return the set of status which holds the status code that assist in presenting notification messages.
  107.      */
  108.     public Set<Status> getStatus() {
  109.         return statusCodes;
  110.     }

  111.     /**
  112.      * Returns true if this MUCUser instance has also {@link Status} information.
  113.      * <p>
  114.      * If <code>true</code> is returned, then {@link #getStatus()} will return a non-empty set.
  115.      * </p>
  116.      *
  117.      * @return true if this MUCUser has status information.
  118.      * @since 4.1
  119.      */
  120.     public boolean hasStatus() {
  121.         return !statusCodes.isEmpty();
  122.     }

  123.     /**
  124.      * Returns the notification that the room has been destroyed. After a room has been destroyed,
  125.      * the room occupants will receive a Presence stanza of type 'unavailable' with the reason for
  126.      * the room destruction if provided by the room owner.
  127.      *
  128.      * @return a notification that the room has been destroyed.
  129.      */
  130.     public Destroy getDestroy() {
  131.         return destroy;
  132.     }

  133.     /**
  134.      * Sets the invitation for another user to a room. The sender of the invitation
  135.      * must be an occupant of the room. The invitation will be sent to the room which in turn
  136.      * will forward the invitation to the invitee.
  137.      *
  138.      * @param invite the invitation for another user to a room.
  139.      */
  140.     public void setInvite(Invite invite) {
  141.         this.invite = invite;
  142.     }

  143.     /**
  144.      * Sets the rejection to an invitation from another user to a room. The rejection will be
  145.      * sent to the room which in turn will forward the refusal to the inviting user.
  146.      *
  147.      * @param decline the rejection to an invitation from another user to a room.
  148.      */
  149.     public void setDecline(Decline decline) {
  150.         this.decline = decline;
  151.     }

  152.     /**
  153.      * Sets the item child that holds information about roles, affiliation, jids and nicks.
  154.      *
  155.      * @param item the item child that holds information about roles, affiliation, jids and nicks.
  156.      */
  157.     public void setItem(MUCItem item) {
  158.         this.item = item;
  159.     }

  160.     /**
  161.      * Sets the password to use to enter Password-Protected Room. A Password-Protected Room is
  162.      * a room that a user cannot enter without first providing the correct password.
  163.      *
  164.      * @param string the password to use to enter Password-Protected Room.
  165.      */
  166.     public void setPassword(String string) {
  167.         password = string;
  168.     }

  169.     /**
  170.      * Add the status codes which holds the codes that assists in presenting notification messages.
  171.      *
  172.      * @param statusCodes the status codes which hold the codes that assists in presenting notification
  173.      * messages.
  174.      */
  175.     public void addStatusCodes(Set<Status> statusCodes) {
  176.         this.statusCodes.addAll(statusCodes);
  177.     }

  178.     /**
  179.      * Add a status code which hold a code that assists in presenting notification messages.
  180.      *
  181.      * @param status the status code which olds a code that assists in presenting notification messages.
  182.      */
  183.     public void addStatusCode(Status status) {
  184.         this.statusCodes.add(status);
  185.     }

  186.     /**
  187.      * Sets the notification that the room has been destroyed. After a room has been destroyed,
  188.      * the room occupants will receive a Presence stanza of type 'unavailable' with the reason for
  189.      * the room destruction if provided by the room owner.
  190.      *
  191.      * @param destroy the notification that the room has been destroyed.
  192.      */
  193.     public void setDestroy(Destroy destroy) {
  194.         this.destroy = destroy;
  195.     }

  196.     /**
  197.      * Retrieve the MUCUser PacketExtension from packet, if any.
  198.      *
  199.      * @param packet TODO javadoc me please
  200.      * @return the MUCUser PacketExtension or {@code null}
  201.      * @deprecated use {@link #from(Stanza)} instead
  202.      */
  203.     @Deprecated
  204.     public static MUCUser getFrom(Stanza packet) {
  205.         return from(packet);
  206.     }

  207.     /**
  208.      * Retrieve the MUCUser PacketExtension from packet, if any.
  209.      *
  210.      * @param packet TODO javadoc me please
  211.      * @return the MUCUser PacketExtension or {@code null}
  212.      */
  213.     public static MUCUser from(Stanza packet) {
  214.         return packet.getExtension(MUCUser.class);
  215.     }

  216.     /**
  217.      * Represents an invitation for another user to a room. The sender of the invitation
  218.      * must be an occupant of the room. The invitation will be sent to the room which in turn
  219.      * will forward the invitation to the invitee.
  220.      *
  221.      * @author Gaston Dombiak
  222.      */
  223.     public static class Invite implements NamedElement {
  224.         public static final String ELEMENT = "invite";

  225.         private final String reason;

  226.         /**
  227.          * From XEP-0045 § 7.8.2: "… whose value is the bare JID, full JID, or occupant JID of the inviting user …"
  228.          */
  229.         private final EntityJid from;

  230.         private final EntityBareJid to;

  231.         public Invite(String reason, EntityFullJid from) {
  232.             this(reason, from, null);
  233.         }

  234.         public Invite(String reason, EntityBareJid to) {
  235.             this(reason, null, to);
  236.         }

  237.         public Invite(String reason, EntityJid from, EntityBareJid to) {
  238.             this.reason = reason;
  239.             this.from = from;
  240.             this.to = to;
  241.         }

  242.         /**
  243.          * Returns the bare JID of the inviting user or, optionally, the room JID. (e.g.
  244.          * 'crone1@shakespeare.lit/desktop').
  245.          *
  246.          * @return the room's occupant that sent the invitation.
  247.          */
  248.         public EntityJid getFrom() {
  249.             return from;
  250.         }

  251.         /**
  252.          * Returns the message explaining the invitation.
  253.          *
  254.          * @return the message explaining the invitation.
  255.          */
  256.         public String getReason() {
  257.             return reason;
  258.         }

  259.         /**
  260.          * Returns the bare JID of the invitee. (e.g. 'hecate@shakespeare.lit')
  261.          *
  262.          * @return the bare JID of the invitee.
  263.          */
  264.         public EntityBareJid getTo() {
  265.             return to;
  266.         }

  267.         @Override
  268.         public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  269.             XmlStringBuilder xml = new XmlStringBuilder(this);
  270.             xml.optAttribute("to", getTo());
  271.             xml.optAttribute("from", getFrom());
  272.             xml.rightAngleBracket();
  273.             xml.optElement("reason", getReason());
  274.             xml.closeElement(this);
  275.             return xml;
  276.         }

  277.         @Override
  278.         public String getElementName() {
  279.             return ELEMENT;
  280.         }
  281.     }

  282.     /**
  283.      * Represents a rejection to an invitation from another user to a room. The rejection will be
  284.      * sent to the room which in turn will forward the refusal to the inviting user.
  285.      *
  286.      * @author Gaston Dombiak
  287.      */
  288.     public static class Decline implements ExtensionElement {
  289.         public static final String ELEMENT = "decline";
  290.         public static final QName QNAME = new QName(NAMESPACE, ELEMENT);

  291.         private final String reason;
  292.         private final EntityBareJid from;
  293.         private final EntityBareJid to;

  294.         public Decline(String reason, EntityBareJid to) {
  295.             this(reason, null, to);
  296.         }

  297.         public Decline(String reason, EntityBareJid from, EntityBareJid to) {
  298.             this.reason = reason;
  299.             this.from = from;
  300.             this.to = to;
  301.         }

  302.         /**
  303.          * Returns the bare JID of the invitee that rejected the invitation. (e.g.
  304.          * 'crone1@shakespeare.lit').
  305.          *
  306.          * @return the bare JID of the invitee that rejected the invitation.
  307.          */
  308.         public EntityBareJid getFrom() {
  309.             return from;
  310.         }

  311.         /**
  312.          * Returns the message explaining why the invitation was rejected.
  313.          *
  314.          * @return the message explaining the reason for the rejection.
  315.          */
  316.         public String getReason() {
  317.             return reason;
  318.         }

  319.         /**
  320.          * Returns the bare JID of the inviting user. (e.g. 'hecate@shakespeare.lit')
  321.          *
  322.          * @return the bare JID of the inviting user.
  323.          */
  324.         public EntityBareJid getTo() {
  325.             return to;
  326.         }

  327.         @Override
  328.         public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  329.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  330.             xml.optAttribute("to", getTo());
  331.             xml.optAttribute("from", getFrom());
  332.             xml.rightAngleBracket();
  333.             xml.optElement("reason", getReason());
  334.             xml.closeElement(this);
  335.             return xml;
  336.         }

  337.         @Override
  338.         public String getElementName() {
  339.             return QNAME.getLocalPart();
  340.         }

  341.         @Override
  342.         public String getNamespace() {
  343.             return QNAME.getNamespaceURI();
  344.         }
  345.     }

  346.     /**
  347.      * Status code assists in presenting notification messages. The following link provides the
  348.      * list of existing error codes <a href="http://xmpp.org/registrar/mucstatus.html">Multi-User Chat Status Codes</a>.
  349.      *
  350.      * @author Gaston Dombiak
  351.      */
  352.     public static final class Status implements NamedElement {
  353.         public static final String ELEMENT = "status";

  354.         private static final Map<Integer, Status> statusMap = new HashMap<>(8);

  355.         public static final Status PRESENCE_TO_SELF_110 = Status.create(110);
  356.         public static final Status ROOM_CREATED_201 = Status.create(201);
  357.         public static final Status BANNED_301 = Status.create(301);
  358.         public static final Status NEW_NICKNAME_303 = Status.create(303);
  359.         public static final Status KICKED_307 = Status.create(307);
  360.         public static final Status REMOVED_AFFIL_CHANGE_321 = Status.create(321);
  361.         public static final Status REMOVED_FOR_TECHNICAL_REASONS_333 = Status.create(333);

  362.         private final Integer code;

  363.         public static Status create(String string) {
  364.             Integer integer = Integer.valueOf(string);
  365.             return create(integer);
  366.         }

  367.         public static Status create(Integer i) {
  368.             Status status;
  369.             // TODO: Use computeIfAbsent once Smack's minimum required Android SDK level is 24 or higher.
  370.             synchronized (statusMap) {
  371.                 status = statusMap.get(i);
  372.                 if (status == null) {
  373.                     status = new Status(i);
  374.                     statusMap.put(i, status);
  375.                 }
  376.             }
  377.             return status;
  378.         }

  379.         /**
  380.          * Creates a new instance of Status with the specified code.
  381.          *
  382.          * @param code the code that uniquely identifies the reason of the error.
  383.          */
  384.         private Status(int code) {
  385.             this.code = code;
  386.         }

  387.         /**
  388.          * Returns the code that uniquely identifies the reason of the error. The code
  389.          * assists in presenting notification messages.
  390.          *
  391.          * @return the code that uniquely identifies the reason of the error.
  392.          */
  393.         public int getCode() {
  394.             return code;
  395.         }

  396.         @Override
  397.         public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  398.             XmlStringBuilder xml = new XmlStringBuilder(this);
  399.             xml.attribute("code", getCode());
  400.             xml.closeEmptyElement();
  401.             return xml;
  402.         }

  403.         @Override
  404.         public String toString() {
  405.             return code.toString();
  406.         }

  407.         @Override
  408.         public boolean equals(Object other) {
  409.             if (other == null) {
  410.                 return false;
  411.             }
  412.             if (other instanceof Status) {
  413.                 Status otherStatus = (Status) other;
  414.                 return code.equals(otherStatus.getCode());
  415.             }
  416.             return false;
  417.         }

  418.         @Override
  419.         public int hashCode() {
  420.             return code;
  421.         }

  422.         @Override
  423.         public String getElementName() {
  424.             return ELEMENT;
  425.         }
  426.     }
  427. }