use of org.jivesoftware.smackx.disco.packet.DiscoverInfo in project Smack by igniterealtime.
the class RoomInfoTest method validateRoomWithEmptyForm.
@Test
public void validateRoomWithEmptyForm() {
DataForm dataForm = new DataForm(DataForm.Type.result);
DiscoverInfo discoInfo = new DiscoverInfo();
discoInfo.addExtension(dataForm);
RoomInfo roomInfo = new RoomInfo(discoInfo);
assertTrue(roomInfo.getDescription().isEmpty());
assertTrue(roomInfo.getSubject().isEmpty());
assertEquals(-1, roomInfo.getOccupantsCount());
}
use of org.jivesoftware.smackx.disco.packet.DiscoverInfo in project Smack by igniterealtime.
the class PingTest method checkSuccessfulDiscoRequest.
@Test
public void checkSuccessfulDiscoRequest() throws Exception {
ThreadedDummyConnection con = getAuthentiactedDummyConnection();
DiscoverInfo info = new DiscoverInfo();
info.addFeature(Ping.NAMESPACE);
//@formatter:off
String reply = "<iq type='result' id='qrzSp-16' to='test@myserver.com'>" + "<query xmlns='http://jabber.org/protocol/disco#info'><identity category='client' type='pc' name='Pidgin'/>" + "<feature var='urn:xmpp:ping'/>" + "</query></iq>";
//@formatter:on
IQ discoReply = (IQ) PacketParserUtils.parseStanza(reply);
con.addIQReply(discoReply);
PingManager pinger = PingManager.getInstanceFor(con);
boolean pingSupported = pinger.isPingSupported(DUMMY_AT_EXAMPLE_ORG);
assertTrue(pingSupported);
}
use of org.jivesoftware.smackx.disco.packet.DiscoverInfo in project Smack by igniterealtime.
the class EntityCapsManager method generateVerificationString.
/**
* Generates a XEP-115 Verification String
*
* @see <a href="http://xmpp.org/extensions/xep-0115.html#ver">XEP-115
* Verification String</a>
*
* @param discoverInfo
* @param hash
* the used hash function, if null, default hash will be used
* @return The generated verification String or null if the hash is not
* supported
*/
protected static CapsVersionAndHash generateVerificationString(DiscoverInfo discoverInfo, String hash) {
if (hash == null) {
hash = DEFAULT_HASH;
}
// SUPPORTED_HASHES uses the format of MessageDigest, which is uppercase, e.g. "SHA-1" instead of "sha-1"
MessageDigest md = SUPPORTED_HASHES.get(hash.toUpperCase(Locale.US));
if (md == null)
return null;
// Then transform the hash to lowercase, as this value will be put on the wire within the caps element's hash
// attribute. I'm not sure if the standard is case insensitive here, but let's assume that even it is, there could
// be "broken" implementation in the wild, so we *always* transform to lowercase.
hash = hash.toLowerCase(Locale.US);
DataForm extendedInfo = DataForm.from(discoverInfo);
// 1. Initialize an empty string S ('sb' in this method).
// Use StringBuilder as we don't
StringBuilder sb = new StringBuilder();
// need thread-safe StringBuffer
// 2. Sort the service discovery identities by category and then by
// type and then by xml:lang
// (if it exists), formatted as CATEGORY '/' [TYPE] '/' [LANG] '/'
// [NAME]. Note that each slash is included even if the LANG or
// NAME is not included (in accordance with XEP-0030, the category and
// type MUST be included.
SortedSet<DiscoverInfo.Identity> sortedIdentities = new TreeSet<DiscoverInfo.Identity>();
for (DiscoverInfo.Identity i : discoverInfo.getIdentities()) sortedIdentities.add(i);
// followed by the '<' character.
for (DiscoverInfo.Identity identity : sortedIdentities) {
sb.append(identity.getCategory());
sb.append('/');
sb.append(identity.getType());
sb.append('/');
sb.append(identity.getLanguage() == null ? "" : identity.getLanguage());
sb.append('/');
sb.append(identity.getName() == null ? "" : identity.getName());
sb.append('<');
}
// 4. Sort the supported service discovery features.
SortedSet<String> features = new TreeSet<String>();
for (Feature f : discoverInfo.getFeatures()) features.add(f.getVar());
// character
for (String f : features) {
sb.append(f);
sb.append('<');
}
// see XEP-0115 5.4 step 3.6
if (extendedInfo != null && extendedInfo.hasHiddenFormTypeField()) {
synchronized (extendedInfo) {
// 6. If the service discovery information response includes
// XEP-0128 data forms, sort the forms by the FORM_TYPE (i.e.,
// by the XML character data of the <value/> element).
SortedSet<FormField> fs = new TreeSet<FormField>(new Comparator<FormField>() {
@Override
public int compare(FormField f1, FormField f2) {
return f1.getVariable().compareTo(f2.getVariable());
}
});
FormField ft = null;
for (FormField f : extendedInfo.getFields()) {
if (!f.getVariable().equals("FORM_TYPE")) {
fs.add(f);
} else {
ft = f;
}
}
// Add FORM_TYPE values
if (ft != null) {
formFieldValuesToCaps(ft.getValues(), sb);
}
// followed by the '<' character.
for (FormField f : fs) {
sb.append(f.getVariable());
sb.append('<');
formFieldValuesToCaps(f.getValues(), sb);
}
}
}
// 8. Ensure that S is encoded according to the UTF-8 encoding (RFC
// 3269).
// 9. Compute the verification string by hashing S using the algorithm
// specified in the 'hash' attribute (e.g., SHA-1 as defined in RFC
// 3174).
// The hashed data MUST be generated with binary output and
// encoded using Base64 as specified in Section 4 of RFC 4648
// (note: the Base64 output MUST NOT include whitespace and MUST set
// padding bits to zero).
byte[] bytes;
try {
bytes = sb.toString().getBytes(StringUtils.UTF8);
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
byte[] digest;
synchronized (md) {
digest = md.digest(bytes);
}
String version = Base64.encodeToString(digest);
return new CapsVersionAndHash(version, hash);
}
use of org.jivesoftware.smackx.disco.packet.DiscoverInfo in project Smack by igniterealtime.
the class DiscoverInfoProvider method parse.
@Override
public DiscoverInfo parse(XmlPullParser parser, int initialDepth) throws Exception {
DiscoverInfo discoverInfo = new DiscoverInfo();
boolean done = false;
DiscoverInfo.Identity identity = null;
String category = "";
String identityName = "";
String type = "";
String variable = "";
String lang = "";
discoverInfo.setNode(parser.getAttributeValue("", "node"));
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
final String name = parser.getName();
final String namespace = parser.getNamespace();
if (namespace.equals(DiscoverInfo.NAMESPACE)) {
switch(name) {
case "identity":
// Initialize the variables from the parsed XML
category = parser.getAttributeValue("", "category");
identityName = parser.getAttributeValue("", "name");
type = parser.getAttributeValue("", "type");
lang = parser.getAttributeValue(parser.getNamespace("xml"), "lang");
break;
case "feature":
// Initialize the variables from the parsed XML
variable = parser.getAttributeValue("", "var");
break;
}
} else // Otherwise, it must be a packet extension.
{
PacketParserUtils.addExtensionElement(discoverInfo, parser);
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("identity")) {
// Create a new identity and add it to the discovered info.
identity = new DiscoverInfo.Identity(category, type, identityName, lang);
discoverInfo.addIdentity(identity);
}
if (parser.getName().equals("feature")) {
// Create a new feature and add it to the discovered info.
boolean notADuplicateFeature = discoverInfo.addFeature(variable);
assert (notADuplicateFeature);
}
if (parser.getName().equals("query")) {
done = true;
}
}
}
return discoverInfo;
}
use of org.jivesoftware.smackx.disco.packet.DiscoverInfo in project Smack by igniterealtime.
the class ServiceDiscoveryManager method findServicesDiscoverInfo.
/**
* Find all services under the users service that provide a given feature.
*
* @param feature the feature to search for
* @param stopOnFirst if true, stop searching after the first service was found
* @param useCache if true, query a cache first to avoid network I/O
* @return a possible empty list of services providing the given feature
* @throws NoResponseException
* @throws XMPPErrorException
* @throws NotConnectedException
* @throws InterruptedException
*/
public List<DiscoverInfo> findServicesDiscoverInfo(String feature, boolean stopOnFirst, boolean useCache) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
List<DiscoverInfo> serviceDiscoInfo = null;
DomainBareJid serviceName = connection().getXMPPServiceDomain();
if (useCache) {
serviceDiscoInfo = services.lookup(feature);
if (serviceDiscoInfo != null) {
return serviceDiscoInfo;
}
}
serviceDiscoInfo = new LinkedList<>();
// Send the disco packet to the server itself
DiscoverInfo info;
try {
info = discoverInfo(serviceName);
} catch (XMPPErrorException e) {
// Be extra robust here: Return the empty linked list and log this situation
LOGGER.log(Level.WARNING, "Could not discover information about service", e);
return serviceDiscoInfo;
}
// Check if the server supports the feature
if (info.containsFeature(feature)) {
serviceDiscoInfo.add(info);
if (stopOnFirst) {
if (useCache) {
// Cache the discovered information
services.put(feature, serviceDiscoInfo);
}
return serviceDiscoInfo;
}
}
DiscoverItems items;
try {
// Get the disco items and send the disco packet to each server item
items = discoverItems(serviceName);
} catch (XMPPErrorException e) {
LOGGER.log(Level.WARNING, "Could not discover items about service", e);
return serviceDiscoInfo;
}
for (DiscoverItems.Item item : items.getItems()) {
try {
// TODO is it OK here in all cases to query without the node attribute?
// MultipleRecipientManager queried initially also with the node attribute, but this
// could be simply a fault instead of intentional.
info = discoverInfo(item.getEntityID());
} catch (XMPPErrorException | NoResponseException e) {
// Don't throw this exceptions if one of the server's items fail
LOGGER.log(Level.WARNING, "Exception while discovering info for feature " + feature + " of " + item.getEntityID() + " node: " + item.getNode(), e);
continue;
}
if (info.containsFeature(feature)) {
serviceDiscoInfo.add(info);
//serviceAddresses.add(item.getEntityID().asDomainBareJid());
if (stopOnFirst) {
break;
}
}
}
if (useCache) {
// Cache the discovered information
services.put(feature, serviceDiscoInfo);
}
return serviceDiscoInfo;
}
Aggregations