예제 #1
0
  public PubSubNodeInfo getNodeDetails(String nodeId) throws SoxLibException {
    PubSubNodeInfo result = new PubSubNodeInfo();
    DiscoverInfo di = null;
    try {
      Node node = mPubSubManager.getNode(nodeId);
      if (!(node instanceof LeafNode)) {
        throw new SoxLibException("Expecting leaf node, but got something else:" + nodeId);
      }
      LeafNode leaf = (LeafNode) node;
      di = leaf.discoverInfo();
    } catch (XMPPException e) {
      throw new SoxLibException("Problem accessing node list:" + nodeId);
    }

    // Expect one and only one identity.
    Iterator<DiscoverInfo.Identity> iter = di.getIdentities();
    if (iter.hasNext()) {
      DiscoverInfo.Identity info = iter.next();
      // logger.log(Level.FINER, "type:" + info.getType());
      // logger.log(Level.FINER, "cat:" + info.getCategory());
      result.nodeType = info.getType();
      // Assert iter.hasNext == false
    }

    // If no form data, returns null for this field.
    result.nodeForm = (DataForm) di.getExtension("jabber:x:data");

    return result;
  }
예제 #2
0
  /**
   * Add {@link DiscoverInfo} to our caps database.
   *
   * <p><b>Warning</b>: The specified <tt>DiscoverInfo</tt> is trusted to be valid with respect to
   * the specified <tt>Caps</tt> for performance reasons because the <tt>DiscoverInfo</tt> should
   * have already been validated in order to be used elsewhere anyway.
   *
   * @param caps the <tt>Caps<tt/> i.e. the node, the hash and the ver for which a
   *     <tt>DiscoverInfo</tt> is to be added to our caps database.
   * @param info {@link DiscoverInfo} for the specified <tt>Caps</tt>.
   */
  public static void addDiscoverInfoByCaps(Caps caps, DiscoverInfo info) {
    cleanupDiscoverInfo(info);
    /*
     * DiscoverInfo carries the node we're now associating it with a
     * specific node so we'd better keep them in sync.
     */
    info.setNode(caps.getNodeVer());

    synchronized (caps2discoverInfo) {
      DiscoverInfo oldInfo = caps2discoverInfo.put(caps, info);

      /*
       * If the specified info is a new association for the specified
       * node, remember it across application instances in order to not
       * query for it over the network.
       */
      if ((oldInfo == null) || !oldInfo.equals(info)) {
        String xml = info.getChildElementXML();

        if ((xml != null) && (xml.length() != 0)) {
          getConfigService().setProperty(getCapsPropertyName(caps), xml);
        }
      }
    }
  }
예제 #3
0
  public void testLocalEntityCaps() throws InterruptedException {
    DiscoverInfo info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecm1.getLocalNodeVer());
    assertFalse(info.containsFeature(DISCOVER_TEST_FEATURE));

    dropWholeEntityCapsCache();

    // This should cause a new presence stanza from con1 with and updated
    // 'ver' String
    sdm1.addFeature(DISCOVER_TEST_FEATURE);

    // Give the server some time to handle the stanza and send it to con0
    Thread.sleep(2000);

    // The presence stanza should get received by con0 and the data should
    // be recorded in the map
    // Note that while both connections use the same static Entity Caps
    // cache,
    // it's assured that *not* con1 added the data to the Entity Caps cache.
    // Every time the entities features
    // and identities change only a new caps 'ver' is calculated and send
    // with the presence stanza
    // The other connection has to receive this stanza and record the
    // information in order for this test to succeed.
    info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecm1.getLocalNodeVer());
    assertNotNull(info);
    assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE));
  }
예제 #4
0
  /**
   * Checks if the given {@linkplain JID} supports the requested feature. The JID may be non
   * resource qualified in which case all presences belonging to that JID are checked.
   *
   * <p>This method does <b>not</b> perform any I/O operation and will return immediately.
   *
   * <p><b>Please note the return value: <code>if(isFeatureSupported(foo, bar)) ... </code> is
   * likely to produce a {@link NullPointerException NPE}.</b>
   *
   * @param jid {@link JID} to query support for
   * @param namespace the namespace of the feature
   * @return <code>true</code> if the given feature is supported, <code>false</code> if it is not
   *     supported or <b><code>null</code> </b> if no information is available
   * @see #queryFeatureSupport(JID, String, boolean)
   */
  public Boolean isFeatureSupported(final JID jid, final String namespace) {
    checkJID(jid);

    Boolean supported = null;

    final List<JID> jidsToQuery = new ArrayList<JID>();

    if (jid.isBareJID()) jidsToQuery.addAll(rosterTracker.getAvailablePresences(jid));
    else jidsToQuery.add(jid);

    for (JID rqJID : jidsToQuery) {

      DiscoverInfoWrapper info = cache.get(rqJID.toString());
      if (info == null) continue;

      DiscoverInfo disco = info.item;

      if (disco == null) continue;

      supported = disco.containsFeature(namespace);

      if (supported) break;
    }

    return supported;
  }
예제 #5
0
  /**
   * Test if entity caps actually prevent a disco info request and reply
   *
   * @throws XMPPException
   */
  public void testPreventDiscoInfo() throws XMPPException {
    con0.addPacketSendingListener(
        new PacketListener() {

          @Override
          public void processPacket(Packet packet) {
            discoInfoSend = true;
          }
        },
        new AndFilter(new PacketTypeFilter(DiscoverInfo.class), new IQTypeFilter(IQ.Type.get)));

    // add a bogus feature so that con1 ver won't match con0's
    sdm1.addFeature(DISCOVER_TEST_FEATURE);

    dropCapsCache();
    // discover that
    DiscoverInfo info = sdm0.discoverInfo(con1.getUser());
    // that discovery should cause a disco#info
    assertTrue(discoInfoSend);
    assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE));
    discoInfoSend = false;

    // discover that
    info = sdm0.discoverInfo(con1.getUser());
    // that discovery shouldn't cause a disco#info
    assertFalse(discoInfoSend);
    assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE));
  }
예제 #6
0
  /**
   * Returns the discovered information of a given XMPP entity addressed by its JID and note
   * attribute. Use this message only when trying to query information which is not directly
   * addressable.
   *
   * @param entityID the address of the XMPP entity.
   * @param node the attribute that supplements the 'jid' attribute.
   * @return the discovered information.
   * @throws XMPPException if the operation failed for some reason.
   */
  public DiscoverInfo discoverInfo(String entityID, String node) throws XMPPException {
    // Discover the entity's info
    DiscoverInfo disco = new DiscoverInfo();
    disco.setType(IQ.Type.GET);
    disco.setTo(entityID);
    disco.setNode(node);

    // Create a packet collector to listen for a response.
    PacketCollector collector =
        connection.createPacketCollector(new PacketIDFilter(disco.getPacketID()));

    connection.sendPacket(disco);

    // Wait up to 5 seconds for a result.
    IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    // Stop queuing results
    collector.cancel();
    if (result == null) {
      throw new XMPPException("No response from the server.");
    }
    if (result.getType() == IQ.Type.ERROR) {
      throw new XMPPException(result.getError());
    }

    return (DiscoverInfo) result;
  }
예제 #7
0
 /**
  * Returns true if the specified user handles XHTML messages.
  *
  * @param connection the connection to use to perform the service discovery
  * @param userID the user to check. A fully qualified xmpp ID, e.g. [email protected]
  * @return a boolean indicating whether the specified user handles XHTML messages
  */
 public static boolean isServiceEnabled(Connection connection, String userID) {
   try {
     DiscoverInfo result = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(userID);
     return result.containsFeature(namespace);
   } catch (XMPPException e) {
     e.printStackTrace();
     return false;
   }
 }
예제 #8
0
  /**
   * Get a DiscoverInfo for the current entity caps node.
   *
   * @return a DiscoverInfo for the current entity caps node
   */
  public DiscoverInfo getOwnDiscoverInfo() {
    DiscoverInfo di = new DiscoverInfo();
    di.setType(IQ.Type.RESULT);
    di.setNode(capsManager.getNode() + "#" + getEntityCapsVersion());

    // Add discover info
    addDiscoverInfoTo(di);

    return di;
  }
예제 #9
0
  /**
   * Perform a service discovery and check if the given feature is among the features supported by
   * the given recipient. All registered listeners will be notified about the result.
   *
   * @param jid A RQ-JID (user@host/resource) of the user to query support for or a non RQ-JID to
   *     query all presences for this JID.
   * @blocking This method blocks until the ServiceDiscovery returns.
   * @reentrant This method can be called concurrently.
   * @caching If results are available in the cache, they are used instead of querying the server.
   */
  private Boolean queryFeatureSupport(JID jid, String namespace) {

    Boolean supported = null;

    checkJID(jid);

    DiscoverInfoWrapper wrapper;

    final List<JID> jidsToQuery = new ArrayList<JID>();

    if (jid.isBareJID()) jidsToQuery.addAll(rosterTracker.getAvailablePresences(jid));
    else jidsToQuery.add(jid);

    for (JID rqJID : jidsToQuery) {

      // add dummy
      synchronized (cache) {
        wrapper = cache.get(rqJID.toString());
        if (wrapper == null) {
          wrapper = new DiscoverInfoWrapper();
          cache.put(rqJID.toString(), wrapper);
        }
      }

      DiscoverInfo disco = null;

      // wait if there is already a discovery for the JID in progress
      synchronized (wrapper) {
        if (wrapper.isAvailable()) disco = wrapper.item;
        else {
          disco = wrapper.item = performServiceDiscovery(rqJID);
          if (disco != null) LOG.debug("Inserted DiscoveryInfo into Cache for: " + rqJID);
        }
      }

      // Null means that the discovery failed
      if (disco == null) {
        // and so we do not know if the feature is supported
        // notifyFeatureSupportUpdated(jid, namespace, false);
        continue;
      }

      notifyFeatureSupportUpdated(rqJID, namespace, disco.containsFeature(namespace));

      /*
       * loop through all presence regardless if we already know that the
       * feature is supported to notify the listener for every current
       * presence
       */
      if (supported != null) supported |= disco.containsFeature(namespace);
      else supported = disco.containsFeature(namespace);
    }

    return supported;
  }
예제 #10
0
  /**
   * Returns the discovered information of a given XMPP entity addressed by its JID if it's known by
   * the entity caps manager.
   *
   * @param entityID the address of the XMPP entity
   * @return the disovered info or null if no such info is available from the entity caps manager.
   * @throws XMPPException if the operation failed for some reason.
   */
  public DiscoverInfo discoverInfoByCaps(String entityID) throws XMPPException {
    DiscoverInfo info = capsManager.getDiscoverInfoByUser(entityID);

    if (info != null) {
      DiscoverInfo newInfo = cloneDiscoverInfo(info);
      newInfo.setFrom(entityID);
      return newInfo;
    } else {
      return null;
    }
  }
예제 #11
0
 /**
  * Get the Discover Information send by your own connection.
  *
  * @return your own DiscoverInfo
  */
 private DiscoverInfo getOwnInformation() {
   DiscoverInfo result = new DiscoverInfo();
   DiscoverInfo.Identity id =
       new DiscoverInfo.Identity("client", ServiceDiscoveryManager.getIdentityName());
   id.setType(ServiceDiscoveryManager.getIdentityType());
   result.addIdentity(id);
   Iterator<String> it = mSdm.getFeatures();
   while (it.hasNext()) {
     result.addFeature(it.next());
   }
   return result;
 }
예제 #12
0
  /**
   * Retrieves the requested node, if it exists. It will throw an exception if it does not.
   *
   * @param id - The unique id of the node
   * @return the node
   * @throws XMPPException The node does not exist
   */
  public Node getNode(String id) throws XMPPException {
    Node node = nodeMap.get(id);

    if (node == null) {
      DiscoverInfo info = new DiscoverInfo();
      info.setTo(to);
      info.setNode(id);

      SyncPacketSend.getReply(con, info);
      node = new Node(con, id);
      node.setTo(to);
      nodeMap.put(id, node);
    }
    return node;
  }
예제 #13
0
  /**
   * Get the identities sorted correctly to calculate the ver attribute.
   *
   * @param info the DiscoverInfo containing the identities
   * @return the sorted list of identities.
   */
  private List<DiscoverInfo.Identity> getSortedIdentity(DiscoverInfo info) {
    List<DiscoverInfo.Identity> result = new ArrayList<DiscoverInfo.Identity>();
    Iterator<DiscoverInfo.Identity> it = info.getIdentities();
    while (it.hasNext()) {
      DiscoverInfo.Identity id = it.next();
      result.add(id);
    }
    Collections.sort(
        result,
        new Comparator<DiscoverInfo.Identity>() {
          public int compare(DiscoverInfo.Identity o1, DiscoverInfo.Identity o2) {

            String cat1 = o1.getCategory();
            if (cat1 == null) cat1 = "";
            String cat2 = o2.getCategory();
            if (cat2 == null) cat2 = "";
            int res = cat1.compareTo(cat2);
            if (res != 0) return res;
            String type1 = o1.getType();
            if (type1 == null) type1 = "";
            String type2 = o2.getCategory();
            if (type2 == null) type2 = "";
            res = type1.compareTo(type2);
            if (res != 0) return res;
            // should compare lang but not avalaible
            return 0;
          }
        });
    return result;
  }
 /** Discover the features provided by the server. */
 private void discoverServerFeatures() {
   try {
     // jid et server
     ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(mAdaptee);
     DiscoverInfo info = sdm.discoverInfo(mAdaptee.getServiceName());
     Iterator<DiscoverInfo.Identity> it = info.getIdentities();
     while (it.hasNext()) {
       DiscoverInfo.Identity identity = it.next();
       if ("pubsub".equals(identity.getCategory()) && "pep".equals(identity.getType())) {
         initPEP();
       }
     }
   } catch (XMPPException e) {
     Log.w(TAG, "Unable to discover server features", e);
   }
 }
예제 #15
0
 /**
  * Tries to discover if the server of the given XMPPConnection provides also a MUC component. Will
  * return the MUCs Component ID if one is found otherwise returns null
  *
  * @param connection
  * @return
  * @throws XMPPException
  */
 public static String disocverMUC(XMPPConnection connection) throws XMPPException {
   ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection);
   DiscoverItems ditem = sdm.discoverItems(connection.getServiceName());
   Iterator<Item> it = ditem.getItems();
   while (it.hasNext()) {
     Item i = it.next();
     DiscoverInfo dinfo = sdm.discoverInfo(i.getEntityID());
     Iterator<Feature> itFeatures = dinfo.getFeatures();
     while (itFeatures.hasNext()) {
       Feature f = itFeatures.next();
       if (f.getVar().equals(MUC_FEATURE)) {
         return i.getEntityID();
       }
     }
   }
   return null;
 }
예제 #16
0
  public void testEntityCaps() throws XMPPException, InterruptedException {
    dropWholeEntityCapsCache();
    sdm1.addFeature(DISCOVER_TEST_FEATURE);

    Thread.sleep(3000);

    DiscoverInfo info = sdm0.discoverInfo(con1.getUser());
    assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE));

    String u1ver = EntityCapsManager.getNodeVersionByJid(con1.getUser());
    assertNotNull(u1ver);

    DiscoverInfo entityInfo = EntityCapsManager.caps.get(u1ver);
    assertNotNull(entityInfo);

    assertEquals(info.toXML(), entityInfo.toXML());
  }
 /**
  * Checks the service discovery item returned from a server component to verify if it is a File
  * Transfer proxy or not.
  *
  * @param manager the service discovery manager which will be used to query the component
  * @param item the discovered item on the server relating
  * @return returns the JID of the proxy if it is a proxy or null if the item is not a proxy.
  */
 private String checkIsProxy(ServiceDiscoveryManager manager, DiscoverItems.Item item) {
   DiscoverInfo info;
   try {
     info = manager.discoverInfo(item.getEntityID());
   } catch (XMPPException e) {
     return null;
   }
   Iterator itx = info.getIdentities();
   while (itx.hasNext()) {
     DiscoverInfo.Identity identity = (DiscoverInfo.Identity) itx.next();
     if ("proxy".equalsIgnoreCase(identity.getCategory())
         && "bytestreams".equalsIgnoreCase(identity.getType())) {
       return info.getFrom();
     }
   }
   return null;
 }
예제 #18
0
  /**
   * Add discover info response data.
   *
   * @param response the discover info response packet
   */
  public void addDiscoverInfoTo(DiscoverInfo response) {
    // Set this client identity
    DiscoverInfo.Identity identity = new DiscoverInfo.Identity("client", getIdentityName());
    identity.setType(getIdentityType());
    response.addIdentity(identity);
    // Add the registered features to the response
    synchronized (features) {
      // Add Entity Capabilities (XEP-0115) feature node.
      response.addFeature("http://jabber.org/protocol/caps");

      for (Iterator<String> it = getFeatures(); it.hasNext(); ) {
        response.addFeature(it.next());
      }
      if (extendedInfo != null) {
        response.addExtension(extendedInfo);
      }
    }
  }
예제 #19
0
  /**
   * Retrieves the requested node, if it exists. It will throw an exception if it does not.
   *
   * @param id - The unique id of the node
   * @return the node
   * @throws XMPPException The node does not exist
   */
  public Node getNode(String id) throws XMPPException {
    Node node = nodeMap.get(id);

    if (node == null) {
      DiscoverInfo info = new DiscoverInfo();
      info.setTo(to);
      info.setNode(id);

      DiscoverInfo infoReply = (DiscoverInfo) SyncPacketSend.getReply(con, info);

      if (infoReply.getIdentities().next().getType().equals(NodeType.leaf.toString()))
        node = new LeafNode(con, id);
      else node = new CollectionNode(con, id);
      node.setTo(to);
      nodeMap.put(id, node);
    }
    return node;
  }
예제 #20
0
    /**
     * Determines whether a specific <tt>DiscoverInfo</tt> is valid according to this <tt>Caps</tt>
     * i.e. whether the <tt>discoverInfo</tt> has the node and the ver of this <tt>Caps</tt> and the
     * ver calculated from the <tt>discoverInfo</tt> using the hash (algorithm) of this
     * <tt>Caps</tt> is equal to the ver of this <tt>Caps</tt>.
     *
     * @param discoverInfo the <tt>DiscoverInfo</tt> to be validated by this <tt>Caps</tt>
     * @return <tt>true</tt> if the specified <tt>DiscoverInfo</tt> has the node and the ver of this
     *     <tt>Caps</tt> and the ver calculated from the <tt>discoverInfo</tt> using the hash
     *     (algorithm) of this <tt>Caps</tt> is equal to the ver of this <tt>Caps</tt>; otherwise,
     *     <tt>false</tt>
     */
    public boolean isValid(DiscoverInfo discoverInfo) {
      if (discoverInfo != null) {
        // The "node" attribute is not necessary in the query element.
        // For example, Swift does not send back the "node" attribute in
        // the Disco#info response. Thus, if the node of the IQ response
        // is null, then we set it to the request one.
        if (discoverInfo.getNode() == null) {
          discoverInfo.setNode(getNodeVer());
        }

        if (getNodeVer().equals(discoverInfo.getNode())
            && !hash.equals("")
            && ver.equals(capsToHash(hash, calculateEntityCapsString(discoverInfo)))) {
          return true;
        }
      }
      return false;
    }
예제 #21
0
 /**
  * Get the features sorted correctly to calculate the ver attribute.
  *
  * @param info the DiscoverInfo containing the features
  * @return the sorted list of features.
  */
 private List<String> getSortedFeature(DiscoverInfo info) {
   List<String> result = new ArrayList<String>();
   Iterator<DiscoverInfo.Feature> it = info.getFeatures();
   while (it.hasNext()) {
     DiscoverInfo.Feature feat = it.next();
     result.add(feat.getVar());
   }
   Collections.sort(result);
   return result;
 }
예제 #22
0
 private boolean checkIfPrivacyIsSupported(XMPPConnection conn) {
   ServiceDiscoveryManager servDisc = ServiceDiscoveryManager.getInstanceFor(conn);
   DiscoverInfo info = null;
   try {
     String xmppHost = DNSUtil.resolveXMPPDomain(conn.getServiceName()).getHost();
     info = servDisc.discoverInfo(xmppHost);
   } catch (XMPPException e) {
     // We could not query the server
     return false;
   }
   if (info != null) {
     for (Iterator<Feature> i = info.getFeatures(); i.hasNext(); ) {
       String s = i.next().getVar();
       if (s.contains("jabber:iq:privacy")) {
         return true;
       }
     }
   }
   return false;
 }
예제 #23
0
  /**
   * Set our own caps version.
   *
   * @param discoverInfo the {@link DiscoverInfo} that we'd like to map to the <tt>capsVersion</tt>.
   * @param capsVersion the new caps version
   */
  public void setCurrentCapsVersion(DiscoverInfo discoverInfo, String capsVersion) {
    Caps caps = new Caps(getNode(), CapsPacketExtension.HASH_METHOD, capsVersion, null);

    /*
     * DiscoverInfo carries the node and the ver and we're now setting a new
     * ver so we should update the DiscoveryInfo.
     */
    discoverInfo.setNode(caps.getNodeVer());

    if (!caps.isValid(discoverInfo)) {
      throw new IllegalArgumentException(
          "The specified discoverInfo must be valid with respect"
              + " to the specified capsVersion");
    }

    currentCapsVersion = capsVersion;
    addDiscoverInfoByCaps(caps, discoverInfo);
    fireCapsVerChanged();
  }
예제 #24
0
 RoomInfo(DiscoverInfo info) {
   super();
   this.room = info.getFrom();
   // Get the information based on the discovered features
   this.membersOnly = info.containsFeature("muc_membersonly");
   this.moderated = info.containsFeature("muc_moderated");
   this.nonanonymous = info.containsFeature("muc_nonanonymous");
   this.passwordProtected = info.containsFeature("muc_passwordprotected");
   this.persistent = info.containsFeature("muc_persistent");
   // Get the information based on the discovered extended information
   Form form = Form.getFormFrom(info);
   if (form != null) {
     this.description = form.getField("muc#roominfo_description").getValues().next();
     Iterator<String> values = form.getField("muc#roominfo_subject").getValues();
     if (values.hasNext()) {
       this.subject = values.next();
     } else {
       this.subject = "";
     }
     this.occupantsCount =
         Integer.parseInt(form.getField("muc#roominfo_occupants").getValues().next());
   }
 }
예제 #25
0
 public static boolean containsFeature(String feature) {
   if (featureInfo == null) return true;
   return featureInfo.containsFeature(feature);
 }
 /**
  * Returns true if the server supports publishing of items. A client may wish to publish items to
  * the server so that the server can provide items associated to the client. These items will be
  * returned by the server whenever the server receives a disco request targeted to the bare
  * address of the client (i.e. [email protected]).
  *
  * @param entityID the address of the XMPP entity.
  * @return true if the server supports publishing of items.
  * @throws XMPPException if the operation failed for some reason.
  */
 public boolean canPublishItems(String entityID) throws XMPPException {
   DiscoverInfo info = discoverInfo(entityID);
   return info.containsFeature("http://jabber.org/protocol/disco#publish");
 }
예제 #27
0
 /**
  * Returns true if the server supports Flexible Offline Message Retrieval. When the server
  * supports Flexible Offline Message Retrieval it is possible to get the header of the offline
  * messages, get specific messages, delete specific messages, etc.
  *
  * @return a boolean indicating if the server supports Flexible Offline Message Retrieval.
  * @throws XMPPException If the user is not allowed to make this request.
  */
 public boolean supportsFlexibleRetrieval() throws XMPPException {
   DiscoverInfo info = ServiceDiscoveryManager.getInstanceFor(connection).discoverInfo(null);
   return info.containsFeature(namespace);
 }
예제 #28
0
  /**
   * Calculates the <tt>String</tt> for a specific <tt>DiscoverInfo</tt> which is to be hashed in
   * order to compute the ver string for that <tt>DiscoverInfo</tt>.
   *
   * @param discoverInfo the <tt>DiscoverInfo</tt> for which the <tt>String</tt> to be hashed in
   *     order to compute its ver string is to be calculated
   * @return the <tt>String</tt> for <tt>discoverInfo</tt> which is to be hashed in order to compute
   *     its ver string
   */
  private static String calculateEntityCapsString(DiscoverInfo discoverInfo) {
    StringBuilder bldr = new StringBuilder();

    // Add identities
    {
      Iterator<DiscoverInfo.Identity> identities = discoverInfo.getIdentities();
      SortedSet<DiscoverInfo.Identity> is =
          new TreeSet<DiscoverInfo.Identity>(
              new Comparator<DiscoverInfo.Identity>() {
                public int compare(DiscoverInfo.Identity i1, DiscoverInfo.Identity i2) {
                  int category = i1.getCategory().compareTo(i2.getCategory());

                  if (category != 0) return category;

                  int type = i1.getType().compareTo(i2.getType());

                  if (type != 0) return type;

                  /*
                   * TODO Sort by xml:lang.
                   *
                   * Since sort by xml:lang is currently missing,
                   * use the last supported sort criterion i.e.
                   * type.
                   */
                  return type;
                }
              });

      if (identities != null) while (identities.hasNext()) is.add(identities.next());

      for (DiscoverInfo.Identity i : is) {
        bldr.append(i.getCategory())
            .append('/')
            .append(i.getType())
            .append("//")
            .append(i.getName())
            .append('<');
      }
    }

    // Add features
    {
      Iterator<DiscoverInfo.Feature> features = getDiscoverInfoFeatures(discoverInfo);
      SortedSet<String> fs = new TreeSet<String>();

      if (features != null) while (features.hasNext()) fs.add(features.next().getVar());

      for (String f : fs) bldr.append(f).append('<');
    }

    DataForm extendedInfo = (DataForm) discoverInfo.getExtension("x", "jabber:x:data");

    if (extendedInfo != null) {
      synchronized (extendedInfo) {
        SortedSet<FormField> fs =
            new TreeSet<FormField>(
                new Comparator<FormField>() {
                  public int compare(FormField f1, FormField f2) {
                    return f1.getVariable().compareTo(f2.getVariable());
                  }
                });

        FormField formType = null;

        for (Iterator<FormField> fieldsIter = extendedInfo.getFields(); fieldsIter.hasNext(); ) {
          FormField f = fieldsIter.next();
          if (!f.getVariable().equals("FORM_TYPE")) fs.add(f);
          else formType = f;
        }

        // Add FORM_TYPE values
        if (formType != null) formFieldValuesToCaps(formType.getValues(), bldr);

        // Add the other values
        for (FormField f : fs) {
          bldr.append(f.getVariable()).append('<');
          formFieldValuesToCaps(f.getValues(), bldr);
        }
      }
    }

    return bldr.toString();
  }
예제 #29
0
 /**
  * Returns true if the server supports publishing of items. A client may wish to publish items to
  * the server so that the server can provide items associated to the client. These items will be
  * returned by the server whenever the server receives a disco request targeted to the bare
  * address of the client (i.e. [email protected]).
  *
  * @param DiscoverInfo the discover info packet to check.
  * @return true if the server supports publishing of items.
  */
 public static boolean canPublishItems(DiscoverInfo info) {
   return info.containsFeature("http://jabber.org/protocol/disco#publish");
 }
예제 #30
0
 private DiscoverInfo cloneDiscoverInfo(DiscoverInfo disco) {
   return disco.clone();
 }