RoomInfo.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;

  18. import java.net.MalformedURLException;
  19. import java.net.URL;
  20. import java.util.Collections;
  21. import java.util.List;
  22. import java.util.logging.Level;
  23. import java.util.logging.Logger;

  24. import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
  25. import org.jivesoftware.smackx.xdata.FormField;
  26. import org.jivesoftware.smackx.xdata.packet.DataForm;

  27. import org.jxmpp.jid.EntityBareJid;
  28. import org.jxmpp.jid.Jid;
  29. import org.jxmpp.jid.util.JidUtil;

  30. /**
  31.  * Represents the room information that was discovered using Service Discovery. It's possible to
  32.  * obtain information about a room before joining the room but only for rooms that are public (i.e.
  33.  * rooms that may be discovered).
  34.  *
  35.  * @author Gaston Dombiak
  36.  */
  37. public class RoomInfo {

  38.     private static final Logger LOGGER = Logger.getLogger(RoomInfo.class.getName());

  39.     /**
  40.      * JID of the room. The localpart of the JID is commonly used as the ID of the room or name.
  41.      */
  42.     private final EntityBareJid room;
  43.     /**
  44.      * Description of the room.
  45.      */
  46.     private final String description;

  47.     /**
  48.      * Name of the room.
  49.      */
  50.     private final String name;

  51.     /**
  52.      * Last known subject of the room.
  53.      */
  54.     private final String subject;
  55.     /**
  56.      * Current number of occupants in the room.
  57.      */
  58.     private final int occupantsCount;
  59.     /**
  60.      * A room is considered members-only if an invitation is required in order to enter the room.
  61.      * Any user that is not a member of the room won't be able to join the room unless the user
  62.      * decides to register with the room (thus becoming a member).
  63.      */
  64.     private final boolean membersOnly;
  65.     /**
  66.      * Moderated rooms enable only participants to speak. Users that join the room and aren't
  67.      * participants can't speak (they are just visitors).
  68.      */
  69.     private final boolean moderated;
  70.     /**
  71.      * Every presence stanza can include the JID of every occupant unless the owner deactivates this
  72.      * configuration.
  73.      */
  74.     private final boolean nonanonymous;
  75.     /**
  76.      * Indicates if users must supply a password to join the room.
  77.      */
  78.     private final boolean passwordProtected;
  79.     /**
  80.      * Persistent rooms are saved to the database to make sure that rooms configurations can be
  81.      * restored in case the server goes down.
  82.      */
  83.     private final boolean persistent;

  84.     /**
  85.      * Maximum number of history messages returned by the room.
  86.      */
  87.     private final int maxhistoryfetch;

  88.     /**
  89.      * Contact Address
  90.      */
  91.     private final List<EntityBareJid> contactJid;

  92.     /**
  93.      * Natural Language for Room Discussions
  94.      */
  95.     private final String lang;

  96.     /**
  97.      * An associated LDAP group that defined room membership. Should be an LDAP
  98.      * Distinguished Name
  99.      */
  100.     private final String ldapgroup;

  101.     /**
  102.      * True if the room subject can be modified by participants
  103.      */
  104.     private final Boolean subjectmod;

  105.     /**
  106.      * URL for archived discussion logs
  107.      */
  108.     private final URL logs;

  109.     /**
  110.      * An associated pubsub node
  111.      */
  112.     private final String pubsub;

  113.     /**
  114.      * The rooms extended configuration form;
  115.      */
  116.     private final DataForm form;

  117.     RoomInfo(DiscoverInfo info) {
  118.         final Jid from = info.getFrom();
  119.         if (from != null) {
  120.             this.room = info.getFrom().asEntityBareJidIfPossible();
  121.         } else {
  122.             this.room = null;
  123.         }
  124.         // Get the information based on the discovered features
  125.         this.membersOnly = info.containsFeature("muc_membersonly");
  126.         this.moderated = info.containsFeature("muc_moderated");
  127.         this.nonanonymous = info.containsFeature("muc_nonanonymous");
  128.         this.passwordProtected = info.containsFeature("muc_passwordprotected");
  129.         this.persistent = info.containsFeature("muc_persistent");

  130.         List<DiscoverInfo.Identity> identities = info.getIdentities();
  131.         // XEP-45 6.4 is not really clear on the topic if an identity needs to
  132.         // be send together with the disco result and how to call this description.
  133.         if (!identities.isEmpty()) {
  134.             this.name = identities.get(0).getName();
  135.         } else {
  136.             LOGGER.warning("DiscoverInfo does not contain any Identity: " + info.toXML());
  137.             this.name = "";
  138.         }
  139.         String subject = "";
  140.         int occupantsCount = -1;
  141.         String description = "";
  142.         int maxhistoryfetch = -1;
  143.         List<EntityBareJid> contactJid = null;
  144.         String lang = null;
  145.         String ldapgroup = null;
  146.         Boolean subjectmod = null;
  147.         URL logs = null;
  148.         String pubsub = null;
  149.         // Get the information based on the discovered extended information
  150.         form = DataForm.from(info);
  151.         if (form != null) {
  152.             FormField descField = form.getField("muc#roominfo_description");
  153.             if (descField != null && !descField.getValues().isEmpty()) {
  154.                 // Prefer the extended result description
  155.                 description = descField.getFirstValue();
  156.             }

  157.             FormField subjField = form.getField("muc#roominfo_subject");
  158.             if (subjField != null && !subjField.getValues().isEmpty()) {
  159.                 subject = subjField.getFirstValue();
  160.             }

  161.             FormField occCountField = form.getField("muc#roominfo_occupants");
  162.             if (occCountField != null && !occCountField.getValues().isEmpty()) {
  163.                 occupantsCount = Integer.parseInt(occCountField.getFirstValue());
  164.             }

  165.             FormField maxhistoryfetchField = form.getField("muc#maxhistoryfetch");
  166.             if (maxhistoryfetchField != null && !maxhistoryfetchField.getValues().isEmpty()) {
  167.                 maxhistoryfetch = Integer.parseInt(maxhistoryfetchField.getFirstValue());
  168.             }

  169.             FormField contactJidField = form.getField("muc#roominfo_contactjid");
  170.             if (contactJidField != null && !contactJidField.getValues().isEmpty()) {
  171.                 List<? extends CharSequence> contactJidValues = contactJidField.getValues();
  172.                 contactJid = JidUtil.filterEntityBareJidList(JidUtil.jidSetFrom(contactJidValues));
  173.             }

  174.             FormField langField = form.getField("muc#roominfo_lang");
  175.             if (langField != null && !langField.getValues().isEmpty()) {
  176.                 lang = langField.getFirstValue();
  177.             }

  178.             FormField ldapgroupField = form.getField("muc#roominfo_ldapgroup");
  179.             if (ldapgroupField != null && !ldapgroupField.getValues().isEmpty()) {
  180.                 ldapgroup = ldapgroupField.getFirstValue();
  181.             }

  182.             FormField subjectmodField = form.getField("muc#roominfo_subjectmod");
  183.             if (subjectmodField != null && !subjectmodField.getValues().isEmpty()) {
  184.                 String firstValue = subjectmodField.getFirstValue();
  185.                 subjectmod = "true".equals(firstValue) || "1".equals(firstValue);
  186.             }

  187.             FormField urlField = form.getField("muc#roominfo_logs");
  188.             if (urlField != null && !urlField.getValues().isEmpty()) {
  189.                 String urlString = urlField.getFirstValue();
  190.                 try {
  191.                     logs = new URL(urlString);
  192.                 } catch (MalformedURLException e) {
  193.                     LOGGER.log(Level.SEVERE, "Could not parse URL", e);
  194.                 }
  195.             }

  196.             FormField pubsubField = form.getField("muc#roominfo_pubsub");
  197.             if (pubsubField != null && !pubsubField.getValues().isEmpty()) {
  198.                 pubsub = pubsubField.getFirstValue();
  199.             }
  200.         }
  201.         this.description = description;
  202.         this.subject = subject;
  203.         this.occupantsCount = occupantsCount;
  204.         this.maxhistoryfetch = maxhistoryfetch;
  205.         this.contactJid = contactJid;
  206.         this.lang = lang;
  207.         this.ldapgroup = ldapgroup;
  208.         this.subjectmod = subjectmod;
  209.         this.logs = logs;
  210.         this.pubsub = pubsub;
  211.     }

  212.     /**
  213.      * Returns the JID of the room whose information was discovered.
  214.      *
  215.      * @return the JID of the room whose information was discovered.
  216.      */
  217.     public EntityBareJid getRoom() {
  218.         return room;
  219.     }

  220.     /**
  221.      * Returns the room name.
  222.      * <p>
  223.      * The name returned here was provided as value of the name attribute
  224.      * of the returned identity within the disco#info result.
  225.      * </p>
  226.      *
  227.      * @return the name of the room.
  228.      */
  229.     public String getName() {
  230.         return name;
  231.     }

  232.     /**
  233.      * Returns the discovered description of the room.
  234.      * <p>
  235.      * The description returned by this method was provided as value of the form
  236.      * field of the extended disco info result. It may be <code>null</code>.
  237.      * </p>
  238.      *
  239.      * @return the discovered description of the room or null
  240.      */
  241.     public String getDescription() {
  242.         return description;
  243.     }

  244.     /**
  245.      * Returns the discovered subject of the room. The subject may be null if the room does not
  246.      * have a subject.
  247.      *
  248.      * @return the discovered subject of the room or null
  249.      */
  250.     public String getSubject() {
  251.         return subject;
  252.     }

  253.     /**
  254.      * Returns the discovered number of occupants that are currently in the room. If this
  255.      * information was not discovered (i.e. the server didn't send it) then a value of -1 will be
  256.      * returned.
  257.      *
  258.      * @return the number of occupants that are currently in the room or -1 if that information was
  259.      * not provided by the server.
  260.      */
  261.     public int getOccupantsCount() {
  262.         return occupantsCount;
  263.     }

  264.     /**
  265.      * Returns true if the room has restricted the access so that only members may enter the room.
  266.      *
  267.      * @return true if the room has restricted the access so that only members may enter the room.
  268.      */
  269.     public boolean isMembersOnly() {
  270.         return membersOnly;
  271.     }

  272.     /**
  273.      * Returns true if the room enabled only participants to speak. Occupants with a role of
  274.      * visitor won't be able to speak in the room.
  275.      *
  276.      * @return true if the room enabled only participants to speak.
  277.      */
  278.     public boolean isModerated() {
  279.         return moderated;
  280.     }

  281.     /**
  282.      * Returns true if presence packets will include the JID of every occupant.
  283.      *
  284.      * @return true if presence packets will include the JID of every occupant.
  285.      */
  286.     public boolean isNonanonymous() {
  287.         return nonanonymous;
  288.     }

  289.     /**
  290.      * Returns true if users must provide a valid password in order to join the room.
  291.      *
  292.      * @return true if users must provide a valid password in order to join the room.
  293.      */
  294.     public boolean isPasswordProtected() {
  295.         return passwordProtected;
  296.     }

  297.     /**
  298.      * Returns true if the room will persist after the last occupant have left the room.
  299.      *
  300.      * @return true if the room will persist after the last occupant have left the room.
  301.      */
  302.     public boolean isPersistent() {
  303.         return persistent;
  304.     }

  305.     /**
  306.      * Returns the maximum number of history messages which are returned by the
  307.      * room or '-1' if this property is not reported by the room.
  308.      *
  309.      * @return the maximum number of history messages or '-1'
  310.      */
  311.     public int getMaxHistoryFetch() {
  312.         return maxhistoryfetch;
  313.     }

  314.     /**
  315.      * Returns Contact Addresses as JIDs, if such are reported.
  316.      *
  317.      * @return a list of contact addresses for this room.
  318.      */
  319.     public List<EntityBareJid> getContactJids() {
  320.         return Collections.unmodifiableList(contactJid);
  321.     }

  322.     /**
  323.      * Returns the natural language of the room discussion, or <code>null</code>.
  324.      *
  325.      * @return the language of the room discussion or <code>null</code>.
  326.      */
  327.     public String getLang() {
  328.         return lang;
  329.     }

  330.     /**
  331.      * Returns an associated LDAP group that defines room membership. The
  332.      * value should be an LDAP Distinguished Name according to an
  333.      * implementation-specific or deployment-specific definition of a group.
  334.      *
  335.      * @return an associated LDAP group or <code>null</code>
  336.      */
  337.     public String getLdapGroup() {
  338.         return ldapgroup;
  339.     }

  340.     /**
  341.      * Returns an Boolean instance with the value 'true' if the subject can be
  342.      * modified by the room participants, 'false' if not, or <code>null</code>
  343.      * if this information is reported by the room.
  344.      *
  345.      * @return an boolean that is true if the subject can be modified by
  346.      *         participants or <code>null</code>
  347.      */
  348.     public Boolean isSubjectModifiable() {
  349.         return subjectmod;
  350.     }

  351.     /**
  352.      * An associated pubsub node for this room or <code>null</code>.
  353.      *
  354.      * @return the associated pubsub node or <code>null</code>
  355.      */
  356.     public String getPubSub() {
  357.         return pubsub;
  358.     }

  359.     /**
  360.      * Returns the URL where archived discussion logs can be found or
  361.      * <code>null</code> if there is no such URL.
  362.      *
  363.      * @return the URL where archived logs can be found or <code>null</code>
  364.      */
  365.     public URL getLogsUrl() {
  366.         return logs;
  367.     }

  368.     /**
  369.      * Returns the form included in the extended disco info result or
  370.      * <code>null</code> if no such form was sent.
  371.      *
  372.      * @return The room info form or <code>null</code>
  373.      * @see <a
  374.      *      href="http://xmpp.org/extensions/xep-0045.html#disco-roominfo">XEP-45:
  375.      *      Multi User Chat - 6.5 Querying for Room Information</a>
  376.      */
  377.     public DataForm getForm() {
  378.         return form;
  379.     }

  380. }